# TxManager **Repository Path**: vipkwds/txmanager ## Basic Information - **Project Name**: TxManager - **Description**: txmanager 是一个基于GO泛型的通用事务管理器,通过接口抽象实现对任意 ORM 的支持 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-21 - **Last Updated**: 2026-05-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TxManager 通用事务管理器 ## 目录 - [概述](#概述) - [安装](#安装) - [背景阐述](#背景阐述) - [核心接口](#核心接口) - [快速开始](#快速开始) - [使用场景](#使用场景) - [独立事务](#场景一独立事务) - [跨函数事务传递](#场景二跨函数事务传递) - [嵌套事务](#场景三嵌套事务) - [多ORM适配](#场景四多orm适配) - [最佳实践](#最佳实践) - [API 参考](#api-参考) --- ## 概述 `txmanager` 是一个基于泛型的通用事务管理器,通过接口抽象实现对任意 ORM 的支持。 ### 设计理念 | 理念 | 说明 | |------|------| | **接口抽象** | 核心只需 `Commit()` 和 `Rollback()` 两个方法 | | **泛型支持** | 使用 Go 1.18+ 泛型,类型安全 | | **外部注入** | 事务由外部创建并注入,库本身不关心底层 ORM | | **幂等操作** | `Commit`/`Rollback` 支持重复调用不报错 | | **自动处理** | `WithDefer` 实现 "有错回滚、无错提交" | ### 与 v0(原版)对比 | 特性 | v0 (beego only) | 当前版本 | |------|----------------|-----------| | ORM 依赖 | 强耦合 beego orm | 接口抽象,适配任意 ORM | | 泛型 | 无 | Go 1.18+ 泛型 | | 事务创建 | 内部 `orm.NewOrm().Begin()` | 外部注入 | | 事务工厂 | 无 | `GetTxManagerFunc` | --- ## 安装 ```bash go get gitee.com/vipkwds/txmanager ``` ## 背景阐述 **事务的"生命周期归属"问题** ### 传统事务管理的问题 ```go // 问题:谁负责 commit/rollback? func A() { tx, _ := db.Begin() B(tx) // B 出错了,谁回滚? C(tx) // C 成功了,谁 commit? // 结果:责任不清,容易遗漏或重复操作 } ``` ### 实际开发中的痛点 | 问题 | 场景 | |------|------| | **责任模糊** | 3个函数嵌套调用,出错时谁回滚?成功时谁提交? | | **重复操作** | 多个错误处理分支,都可能调用 Rollback | | **遗忘处理** | 函数提前 return,忘记 commit/rollback | | **错误丢失** | 底层错误被上层覆盖 | | **传递繁琐** | 每个子函数都要传递 tx 对象 | ### txmanager 解决的核心问题 ``` ┌─────────────────────────────────────────────────────────┐ │ 事务生命周期归属问题 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 传统方式: │ │ ┌─────────┐ │ │ │ A() │── tx.Begin() │ │ │ │ │ │ │ ┌─────┐│ │ │ │ │ B() ││── 使用 tx │ │ │ └─────┘│ │ │ │ │ ┌─────┐│ │ │ │ │ │ C() ││── 使用 tx │ │ │ └─────┘│ │ │ │ │ │ ↓ │ │ │ ??? │── 谁来 Commit/Rollback ? │ │ └─────────┘ │ │ │ │ txmanager 方式: │ │ ┌─────────────────────────────────────────┐ │ │ │ A() │ │ │ │ tx.Begin() │ │ │ │ txMgr := NewTxManager(tx) │ │ │ │ defer txMgr.WithDefer() ◄────────────│──────────┘│ │ │ │ │ │ │ B(txMgr) ─────► 只管业务,不管事务 │ │ │ │ C(txMgr) ─────► 只管业务,不管事务 │ │ │ │ } │ │ │ │ ◄── 函数退出时 WithDefer 自动处理 │ │ │ └─────────────────────────────────────────┘ │ │ │ │ 结论: 顶级函数拥有事务生命周期,子函数专注业务 │ │ │ └─────────────────────────────────────────────────────────┘ ``` ### 解决方案:三权分立 | 角色 | 职责 | 代码 | |------|------|------| | **顶级函数** | 创建事务 + defer WithDefer + 决定最终处理 | `NewTxManager()` + `defer WithDefer()` | | **子函数** | 接收 txMgr + 执行业务 + 设置错误 | `txMgr.SetError(err) 为事务感知` , `return err 业务态感知` | | **txmanager** | 状态跟踪 + 自动处理 | `isCommitted/isRollbacked` 防止重复 | ### 核心价值 ```go // 原版: 责任分散,容易出错 func Bad() { tx.Begin() if err := Step1(); err != nil { tx.Rollback() // 可能遗忘 return } if err := Step2(); err != nil { tx.Rollback() // 可能遗忘 return } // 可能遗忘 commit } // txmanager: 责任集中,自动处理 func Good() { tx.Begin() txMgr := NewTxManager(tx) defer txMgr.WithDefer() // 必须配合 SetError 或 SetErrorf 才能感知错误 if err := Step1(); err != nil { txMgr.SetError(err) // 必须显式设置错误! return } if err := Step2(); err != nil { txMgr.SetErrorf("step2 failed: %w", err) // 必须显式设置错误! return } // 无错误 → WithDefer 自动提交 } // 关键点:WithDefer 根据 m.err 判断,m.err 需要 SetError 来设置 // - 调用了 SetError(err) → m.err != nil → WithDefer 自动回滚 // - 没有调用 SetError → m.err == nil → WithDefer 自动提交 ``` **一句话总结**:txmanager 解决了"**跨函数调用时,事务生命周期由谁管理**"这个问题 —— 实现了**顶级函数拥有生命周期,子函数专注业务**的模式。 **重要**:子函数出错时必须调用 `SetError(err)` 显式记录错误,否则 WithDefer 感知不到错误,会错误地提交事务! --- ## 核心接口 ### Transaction 接口 ```go // 事务核心接口,只需实现 Commit 和 Rollback type Transaction interface { Commit() error Rollback() error } ``` ### TxManager 结构 ```go type TxManager[T any] struct { tx T // 底层ORM事务对象 isCommitted bool // 是否已提交 isRollbacked bool // 是否已回滚 err error // 累积的错误 hasParent bool // 是否有父事务 parentFunc string // 父事务函数名 } ``` --- ## 快速开始 ### 1. 定义适配器 以 gorm 为例,定义一个包装类型: ```go package adapter import ( "gorm.io/gorm" ) // GormTx 包装 gorm.DB 实现 Transaction 接口 type GormTx struct { DB *gorm.DB } func (g *GormTx) Commit() error { return g.DB.Commit().Error } func (g *GormTx) Rollback() error { return g.DB.Rollback().Error } ``` ### 2. 基本使用 ```go package main import ( "gorm.io/driver/mysql" "gorm.io/gorm" "gitee.com/vipkwds/txmanager" "your_project/adapter" ) func main() { db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{}) // 开启事务 tx := db.Begin() txMgr := txmanager.NewTxManager(adapter.GormTx{DB: tx}) defer txMgr.WithDefer() // 业务操作 user := &User{Name: "张三"} if err := txMgr.Tx().DB.Create(user).Error; err != nil { return txMgr.SetError(err) } // 自动提交或回滚 } ``` --- ## 使用场景 ### 场景一:独立事务 最基础的用法,一个函数内完成事务操作。 #### 适配器定义 ```go // beego orm 适配器 type BeegoTx struct { tx orm.TxOrmer } func (b *BeegoTx) Commit() error { return b.tx.Commit() } func (b *BeegoTx) Rollback() error { return b.tx.Rollback() } ``` #### 使用 ```go func CreateUser(user *User) error { // 1. 开启事务 ormTx, err := orm.NewOrm().Begin() if err != nil { return fmt.Errorf("开启事务失败: %w", err) } // 2. 创建事务管理器 txMgr := txmanager.NewTxManager(BeegoTx{tx: ormTx}) // 3. defer 自动处理 defer txMgr.WithDefer() // 4. 业务操作 if _, err := txMgr.Tx().tx.Insert(user); err != nil { return txMgr.SetError(err) } // 5. 返回 nil,WithDefer 自动提交 // 返回 error,WithDefer 自动回滚 return nil } ``` #### 流程图 ``` CreateUser() │ ├─ 1. Begin() 开启事务 │ ├─ 2. NewTxManager() 创建管理器 │ ├─ 3. defer WithDefer() 注册自动处理 │ ├─ 4. 业务操作 (Insert/Update/Query) │ │ │ └─ 成功: return nil │ └─ 失败: SetError() + return err │ └─ 5. 函数退出时 WithDefer 执行 │ ├─ 无错误 → Commit └─ 有错误 → Rollback ``` --- ### 场景二:跨函数事务传递 最常用的场景,顶级函数创建事务,传递给子函数执行。 #### 适配器(gorm) ```go type GormTx struct { DB *gorm.DB } func (g *GormTx) Commit() error { return g.DB.Commit().Error } func (g *GormTx) Rollback() error { return g.DB.Rollback().Error } ``` #### 顶级函数 ```go // OrderService 订单服务 type OrderService struct { db *gorm.DB } // CreateOrder 创建订单(顶级函数) func (s *OrderService) CreateOrder(order *Order, items []*OrderItem) error { // 1. 开启事务 tx := s.db.Begin() txMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer txMgr.WithDefer() // 2. 创建订单(子函数复用事务) if err := s.createOrder(txMgr, order); err != nil { return err } // 3. 创建订单项(子函数复用事务) for _, item := range items { if err := s.createOrderItem(txMgr, item); err != nil { return err } } // 4. 扣减库存(子函数复用事务) for _, item := range items { if err := s.deductStock(txMgr, item.ProductID, item.Quantity); err != nil { return err } } return nil } ``` #### 子函数 ```go // createOrder 创建订单(子函数,复用事务) func (s *OrderService) createOrder(txMgr *txmanager.TxManager[GormTx], order *Order) error { // 使用 GetTxManager 统一处理 // 当传入 *TxManager 时,自动标记为子事务 if _, err := txMgr.Tx().DB.Insert(order).Error; err != nil { return txMgr.SetError(err) } return nil } // createOrderItem 创建订单项 func (s *OrderService) createOrderItem(txMgr *txmanager.TxManager[GormTx], item *OrderItem) error { if _, err := txMgr.Tx().DB.Insert(item).Error; err != nil { return txMgr.SetError(err) } return nil } // deductStock 扣减库存 func (s *OrderService) deductStock(txMgr *txmanager.TxManager[GormTx], productID, quantity int64) error { // 先查询 var product Product if err := txMgr.Tx().DB.First(&product, productID).Error; err != nil { return txMgr.SetError(err) } // 检查库存 if product.Stock < quantity { return txMgr.SetErrorf("商品 %d 库存不足", productID) } // 扣减库存 product.Stock -= quantity if err := txMgr.Tx().DB.Save(&product).Error; err != nil { return txMgr.SetError(err) } return nil } ``` #### 流程图 ``` CreateOrder() [顶级] │ ├─ Begin() → tx ├─ NewTxManager(tx) ├─ defer WithDefer() │ ├─ createOrder(txMgr) [子函数] │ │ │ └─ Insert(order) │ ├─ createOrderItem(txMgr) [子函数] │ │ │ └─ Insert(item) │ ├─ deductStock(txMgr) [子函数] │ │ │ ├─ Query(product) │ ├─ Check stock │ └─ Update(product) │ └─ WithDefer() │ ├─ 无错误 → Commit └─ 有错误 → Rollback ``` --- ### 场景三:嵌套事务 在子函数中需要独立事务,但又要保证整体一致性。 ```go // 嵌套事务处理函数 func HandleWithNestedTx(txMgr *txmanager.TxManager[GormTx], bizFunc func(tx *txmanager.TxManager[GormTx]) error) error { // 调用者未传递事务,创建新事务 if txMgr == nil { tx := db.Begin() newTxMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer newTxMgr.WithDefer() return bizFunc(newTxMgr) } // 调用者传递了事务,复用 return bizFunc(txMgr) } // 使用 func ComplexBusiness() error { tx := db.Begin() txMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer txMgr.WithDefer() // 某些步骤需要独立事务 return HandleWithNestedTx(txMgr, func(subTx *txmanager.TxManager[GormTx]) error { // subTx 就是 txMgr(复用) if err := subTx.Tx().DB.Create(&Log{Action: "step1"}).Error; err != nil { return subTx.SetError(err) } return nil }) } ``` --- ### 场景四:多ORM适配 同一套业务代码,切换不同 ORM。 #### 4.1 GORM 适配 ```go // gorm_adapter.go type GormDB struct { DB *gorm.DB } type GormTx struct { DB *gorm.DB } func (g *GormTx) Commit() error { return g.DB.Commit().Error } func (g *GormTx) Rollback() error { return g.DB.Rollback().Error } // 工厂函数 func NewGormTxManager(db *gorm.DB) (*txmanager.TxManager[GormTx], error) { tx := db.Begin() if err := tx.Error; err != nil { return nil, err } return txmanager.NewTxManager(GormTx{DB: tx}), nil } ``` #### 4.2 XORM 适配 ```go // xorm_adapter.go type XormTx struct { session *xorm.Session } func (x *XormTx) Commit() error { return x.session.Commit() } func (x *XormTx) Rollback() error { return x.session.Rollback() } type XormDB struct { engine *xorm.Engine } func (x *XormDB) Begin() (*txmanager.TxManager[XormTx], error) { session := x.engine.NewSession() if err := session.Begin(); err != nil { return nil, err } return txmanager.NewTxManager(XormTx{session: session}), nil } ``` #### 4.3 业务代码(与 ORM 无关) ```go // service.go // UserService 业务逻辑,与 ORM 解耦 type UserService struct { txManager any // 泛型接口,运行时确定具体类型 } func (s *UserService) CreateUser(user *User) error { // 这里不需要关心底层是 gorm 还是 xorm // 只需要调用 Tx() 获取底层事务对象 return s.doCreateUser(user) } func (s *UserService) doCreateUser(user *User) error { // 业务逻辑... return nil } ``` --- ### 场景五:使用 GetTxManager 统一入口 `GetTxManager` 支持多种参数类型,自动适配。 ```go // GetTxManager 的工厂参数 type TxFactory func() (any, error) // 顶级函数 func TopLevelFunc(db *gorm.DB) error { // 方式1: nil 参数 + factory,创建新事务 txMgr, cleanup, err := txmanager.GetTxManager[GormTx]( func() (any, error) { tx := db.Begin() return GormTx{DB: tx}, nil }, nil, // nil 表示创建新事务 ) if err != nil { return err } defer cleanup() // 业务操作... return SubFunc(txMgr) } // 子函数 func SubFunc(txOpt any) error { // 方式2: *TxManager,直接复用 txMgr, cleanup, err := txmanager.GetTxManager[GormTx](nil, txOpt) if err != nil { return err } defer cleanup() if err := txMgr.Tx().DB.Create(&User{Name: "test"}).Error; err != nil { return txMgr.SetError(err) } return nil } ``` --- ## 最佳实践 ### 1. 错误处理 ```go // 推荐:SetError + return if err := doSomething(); err != nil { return txMgr.SetError(err) // 必须 SetError,否则 WithDefer 不知道有错 //return err // 直接return err是逻辑层返回错误,事务层无法感知 } // 错误案例:只 return 不 SetError if err := doSomething(); err != nil { return err // WithDefer 不知道有错,会提交! } ``` ### 2. 事务粒度 ```go // 推荐:短事务 func GoodExample() error { tx := db.Begin() txMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer txMgr.WithDefer() // 只在事务内做必要的数据库操作 if err := txMgr.Tx().DB.Save(&order).Error; err != nil { return txMgr.SetError(err) // 必须设置错误 } return nil } // 不推荐:长事务 func BadExample() error { tx := db.Begin() txMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer txMgr.WithDefer() // 复杂计算、远程调用都在事务内... result := complexCalculation() // 不应该放在事务内 if err := txMgr.Tx().DB.Save(&result).Error; err != nil { return txMgr.SetError(err) // 必须设置错误 // return err //错误用法(事务不受控) } return nil } ``` ### 3. 嵌套层级 ```go // 推荐:最多 2-3 层 func Level1() error { txMgr := BeginTx() defer txMgr.WithDefer() if err := Level2(txMgr); err != nil { return err // Level2 已调用 SetError,只需 return } return nil } func Level2(txMgr *txmanager.TxManager[Tx]) error { if err := Level3(txMgr); err != nil { return err } return nil } func Level3(txMgr *txmanager.TxManager[Tx]) error { if err := txMgr.Tx().Insert(...); err != nil { return txMgr.SetError(err) } return nil } ``` --- ## API 参考 ### TxManager[T] ```go // 创建事务管理器 func NewTxManager[T any](tx T) *TxManager[T] // 获取错误 func (m *TxManager[T]) Error() error // 设置错误(仅首次) func (m *TxManager[T]) SetError(err error) error // 设置格式化错误 func (m *TxManager[T]) SetErrorf(format string, args ...any) error // 提交事务(幂等) func (m *TxManager[T]) Commit() error // 回滚事务(幂等) func (m *TxManager[T]) Rollback() error // defer 自动处理 func (m *TxManager[T]) WithDefer() // 获取底层事务对象 func (m *TxManager[T]) Tx() T // 查询状态 func (m *TxManager[T]) IsCommitted() bool func (m *TxManager[T]) IsRollbacked() bool func (m *TxManager[T]) HasParent() bool ``` ### GetTxManager ```go func GetTxManager[T any](factory GetTxManagerFunc, txOpts ...any) (*TxManager[T], func(), error) ``` **参数类型**: | 类型 | 行为 | |------|------| | `nil` | 使用 factory 创建新事务 | | `*TxManager[T]` | 复用已有事务管理器 | | `T` | 传入已开启的事务对象 | **返回值**: | 值 | 说明 | |---|------| | `*TxManager[T]` | 事务管理器 | | `func()` | cleanup 函数,需在 defer 中调用 | | `error` | 错误信息 | --- ## 完整示例 ### GORM 完整示例 ```go package main import ( "fmt" "gorm.io/driver/mysql" "gorm.io/gorm" ) /* # 安装依赖 go get gorm.io/gorm go get gorm.io/driver/mysql # 运行示例 go run examples/gorm_complete_example.go */ // ============================================================================ // 1. 定义适配器 // ============================================================================ type GormTx struct { DB *gorm.DB } func (g *GormTx) Commit() error { return g.DB.Commit().Error } func (g *GormTx) Rollback() error { return g.DB.Rollback().Error } // ============================================================================ // 2. 定义模型 // ============================================================================ type User struct { ID uint Name string Age int } type Order struct { ID uint UserID uint Amount float64 Status string } // ============================================================================ // 3. 业务服务 // ============================================================================ type UserService struct { db *gorm.DB } func NewUserService(db *gorm.DB) *UserService { return &UserService{db: db} } // CreateUserWithOrder 创建用户和订单(顶级事务) func (s *UserService) CreateUserWithOrder(user *User, amount float64) error { // 开启事务 tx := s.db.Begin() txMgr := txmanager.NewTxManager(GormTx{DB: tx}) defer txMgr.WithDefer() // 创建用户 if err := s.createUser(txMgr, user); err != nil { return err } // 创建订单 order := &Order{ UserID: user.ID, Amount: amount, Status: "pending", } if err := s.createOrder(txMgr, order); err != nil { return err } return nil } func (s *UserService) createUser(txMgr *txmanager.TxManager[GormTx], user *User) error { if err := txMgr.Tx().DB.Create(user).Error; err != nil { return txMgr.SetError(err) } return nil } func (s *UserService) createOrder(txMgr *txmanager.TxManager[GormTx], order *Order) error { if err := txMgr.Tx().DB.Create(order).Error; err != nil { return txMgr.SetError(err) } return nil } // ============================================================================ // 4. 主函数 // ============================================================================ func main() { db, err := gorm.Open(mysql.Open("root:password@tcp(localhost:3306)/test?charset=utf8mb4"), &gorm.Config{}) if err != nil { panic(err) } service := NewUserService(db) user := &User{Name: "张三", Age: 30} if err := service.CreateUserWithOrder(user, 100.0); err != nil { fmt.Printf("创建失败: %v\n", err) return } fmt.Printf("创建成功: user=%+v\n", user) } ``` --- ## 总结 `txmanager` 通过以下设计实现通用性: 1. **接口抽象**:仅需 `Commit()` 和 `Rollback()` 2. **泛型支持**:类型安全,IDE 友好 3. **外部注入**:事务创建由外部控制,库不依赖特定 ORM 4. **统一入口**:`GetTxManager` 支持多种参数类型 5. **状态跟踪**:防止重复提交/回滚 **适配新 ORM 只需**: 1. 定义包装类型实现 `Transaction` 接口 2. 在 `Tx()` 方法中返回底层事务对象供业务调用 --- ## 重要:必须显式设置错误 `WithDefer` 的自动处理逻辑依赖 `m.err` 状态: ```go func (m *TxManager[T]) WithDefer() { if m.isCommitted || m.isRollbacked { return } if m.err != nil { // ← m.err 需要通过 SetError 来设置 m.Rollback() // 有错误 → 回滚 } else { m.Commit() // 无错误 → 提交 } } ``` **常见错误**: ```go // ❌ 错误:只 return 不 SetError,WithDefer 不知道有错,会提交! if err := doSomething(); err != nil { return err } // ✓ 正确:SetError + return if err := doSomething(); err != nil { return txMgr.SetError(err) } ```