golang多适配器事务管理插件库go-transaction-manager的使用

Go Transaction Manager 使用指南

概述

Go Transaction Manager 是一个用于协调数据库事务边界的抽象层,支持多种数据库适配器。

支持的实现

  • database/sql (Go 1.13+)
  • jmoiron/sqlx (Go 1.13+)
  • gorm (Go 1.18+)
  • mongo-go-driver (Go 1.13+)
  • go-redis/redis (Go 1.17+)
  • pgx_v4 (Go 1.16+)
  • pgx_v5 (Go 1.19+)

安装

go get github.com/avito-tech/go-transaction-manager/trm/v2

要安装特定数据库支持,例如 sqlx:

go get github.com/avito-tech/go-transaction-manager/drivers/sqlx/v2

使用示例

以下是一个完整的 SQLx 适配器使用示例:

package main

import (
	"context"
	"fmt"

	"github.com/jmoiron/sqlx"
	_ "github.com/mattn/go-sqlite3"

	trmsqlx "github.com/avito-tech/go-transaction-manager/drivers/sqlx/v2"
	"github.com/avito-tech/go-transaction-manager/trm/v2/manager"
)

func main() {
	// 初始化数据库连接
	db, err := sqlx.Open("sqlite3", "file:test?mode=memory")
	checkErr(err)
	defer db.Close()

	// 创建测试表
	sqlStmt := `CREATE TABLE IF NOT EXISTS user (user_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, username TEXT);`
	_, err = db.Exec(sqlStmt)
	checkErr(err, sqlStmt)

	// 初始化repository和事务管理器
	r := newRepo(db, trmsqlx.DefaultCtxGetter)
	ctx := context.Background()
	trManager := manager.Must(trmsqlx.NewDefaultFactory(db))
	u := &user{Username: "username"}

	// 执行事务操作
	err = trManager.Do(ctx, func(ctx context.Context) error {
		checkErr(r.Save(ctx, u))

		// 嵌套事务示例
		return trManager.Do(ctx, func(ctx context.Context) error {
			u.Username = "new_username"
			return r.Save(ctx, u)
		})
	})
	checkErr(err)

	// 查询数据
	userFromDB, err := r.GetByID(ctx, u.ID)
	checkErr(err)

	fmt.Println(userFromDB)
}

func checkErr(err error, args ...interface{}) {
	if err != nil {
		panic(fmt.Sprint(append([]interface{}{err}, args...)...))
	}
}

// 定义repository结构体
type repo struct {
	db     *sqlx.DB
	getter *trmsqlx.CtxGetter
}

func newRepo(db *sqlx.DB, c *trmsqlx.CtxGetter) *repo {
	return &repo{db: db, getter: c}
}

// 定义用户模型
type user struct {
	ID       int64  `db:"user_id"`
	Username string `db:"username"`
}

// 根据ID获取用户
func (r *repo) GetByID(ctx context.Context, id int64) (*user, error) {
	query := "SELECT * FROM user WHERE user_id = ?;"
	u := user{}

	return &u, r.getter.DefaultTrOrDB(ctx, r.db).GetContext(ctx, &u, r.db.Rebind(query), id)
}

// 保存用户
func (r *repo) Save(ctx context.Context, u *user) error {
	query := `UPDATE user SET username = :username WHERE user_id = :user_id;`
	if u.ID == 0 {
		query = `INSERT INTO user (username) VALUES (:username);`
	}

	res, err := sqlx.NamedExecContext(ctx, r.getter.DefaultTrOrDB(ctx, r.db), r.db.Rebind(query), u)
	if err != nil {
		return err
	} else if u.ID != 0 {
		return nil
	} else if u.ID, err = res.LastInsertId(); err != nil {
		return err
	}

	return err
}

关键特性说明

  1. 多数据库事务:需要在Settings中通过WithCtxKey设置CtxKey
  2. 嵌套事务:对于不同的事务管理器,需要使用ChainedMW
  3. 跳过回滚:可以使用ErrSkip或Skippable来跳过由于错误导致的事务回滚

最佳实践

  1. 使用go get -u && go mod tidy保持依赖更新
  2. 该库兼容最近两个Go版本,建议使用最新版本
  3. 对于生产环境,建议使用真实数据库进行集成测试

注意事项

  1. 该库使用了一些旧版依赖以支持旧版Go的向后兼容性
  2. 对于旧版Go支持,可能需要手动设置某些库的版本

更多关于golang多适配器事务管理插件库go-transaction-manager的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang多适配器事务管理插件库go-transaction-manager的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


go-transaction-manager 使用指南

go-transaction-manager 是一个用于 Golang 的多适配器事务管理库,它提供了统一的事务管理接口,支持多种数据库和存储引擎。

核心特性

  • 支持多种适配器:PostgreSQL、MySQL、MongoDB、Redis 等
  • 统一的事务管理接口
  • 支持嵌套事务
  • 上下文感知的事务管理

安装

go get github.com/avito-tech/go-transaction-manager

基本使用

1. 初始化事务管理器

import (
    "context"
    "database/sql"
    "github.com/avito-tech/go-transaction-manager/trm"
    "github.com/avito-tech/go-transaction-manager/trm/sqlx"
    _ "github.com/lib/pq"
)

func main() {
    // 初始化数据库连接
    db, err := sql.Open("postgres", "postgres://user:password@localhost/dbname?sslmode=disable")
    if err != nil {
        panic(err)
    }
    
    // 创建事务管理器
    trManager := sqlx.NewDefaultFactory(db)
    
    // 使用事务管理器
    ctx := context.Background()
    err = trManager.Do(ctx, func(ctx context.Context) error {
        // 业务逻辑代码
        return nil
    })
    
    if err != nil {
        // 处理错误
    }
}

2. 嵌套事务示例

func processOrder(ctx context.Context, trManager trm.Manager) error {
    return trManager.Do(ctx, func(ctx context.Context) error {
        // 主事务逻辑
        
        // 嵌套事务1
        err := trManager.Do(ctx, func(ctx context.Context) error {
            // 更新库存
            return nil
        })
        if err != nil {
            return err
        }
        
        // 嵌套事务2
        err = trManager.Do(ctx, func(ctx context.Context) error {
            // 创建订单
            return nil
        })
        
        return err
    })
}

3. 获取事务对象

func updateUser(ctx context.Context, trManager trm.Manager, userID int, name string) error {
    return trManager.Do(ctx, func(ctx context.Context) error {
        // 从上下文中获取事务对象
        tr, ok := trm.FromContext(ctx)
        if !ok {
            return errors.New("transaction not found")
        }
        
        // 类型断言为具体的事务类型
        sqlTr, ok := tr.(*sql.Tx)
        if !ok {
            return errors.New("invalid transaction type")
        }
        
        // 使用事务执行SQL
        _, err := sqlTr.ExecContext(ctx, "UPDATE users SET name = $1 WHERE id = $2", name, userID)
        return err
    })
}

多适配器支持

1. MongoDB 适配器示例

import (
    "go.mongodb.org/mongo-driver/mongo"
    "github.com/avito-tech/go-transaction-manager/trm/mongo"
)

func main() {
    client, err := mongo.Connect(context.Background(), options.Client().ApplyURI("mongodb://localhost:27017"))
    if err != nil {
        panic(err)
    }
    
    trManager := mongo.NewDefaultFactory(client)
    
    err = trManager.Do(context.Background(), func(ctx context.Context) error {
        collection := client.Database("test").Collection("users")
        _, err := collection.InsertOne(ctx, bson.M{"name": "John"})
        return err
    })
}

2. Redis 适配器示例

import (
    "github.com/redis/go-redis/v9"
    "github.com/avito-tech/go-transaction-manager/trm/redis"
)

func main() {
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "",
        DB:       0,
    })
    
    trManager := redis.NewDefaultFactory(rdb)
    
    err := trManager.Do(context.Background(), func(ctx context.Context) error {
        err := rdb.Set(ctx, "key", "value", 0).Err()
        return err
    })
}

高级配置

1. 自定义事务设置

func main() {
    db, _ := sql.Open("postgres", "postgres://...")
    
    // 自定义事务设置
    settings := sqlx.NewSettings(
        sqlx.WithIsolationLevel(sql.LevelSerializable),
        sqlx.WithReadOnly(false),
    )
    
    trManager := sqlx.New(db, settings)
    
    // 使用事务管理器...
}

2. 事务传播行为

func main() {
    db, _ := sql.Open("postgres", "postgres://...")
    trManager := sqlx.NewDefaultFactory(db)
    
    ctx := context.Background()
    
    // REQUIRED (默认): 如果存在事务则加入,否则新建
    err := trManager.Do(ctx, func(ctx context.Context) error {
        // 业务逻辑
        
        // REQUIRES_NEW: 总是新建事务
        return trManager.Do(trm.NewPropagation(ctx, trm.PropagationRequiresNew), func(ctx context.Context) error {
            // 独立事务逻辑
            return nil
        }
    })
}

最佳实践

  1. 事务边界:合理划分事务边界,避免过长事务
  2. 错误处理:正确处理事务中的错误,确保事务能够正确回滚
  3. 上下文传递:始终传递上下文,确保事务能够正确传播
  4. 隔离级别:根据业务需求选择合适的隔离级别

总结

go-transaction-manager 提供了统一的事务管理接口,简化了多数据源环境下的事务管理。通过适配器模式,它可以轻松集成到现有项目中,并提供灵活的事务控制能力。

回到顶部