本文主要研究一下gorm的Transaction
gorm.io/gorm@v1.20.10/finisher_api.go
// Transaction start a transaction as a block, return error will rollback, otherwise to commit. func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) { panicked := true if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil { // nested transaction if !db.DisableNestedTransaction { err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error defer func() { // Make sure to rollback when panic, Block error or Commit error if panicked || err != nil { db.RollbackTo(fmt.Sprintf("sp%p", fc)) } }() } if err == nil { err = fc(db.Session(&Session{})) } } else { tx := db.Begin(opts...) defer func() { // Make sure to rollback when panic, Block error or Commit error if panicked || err != nil { tx.Rollback() } }() if err = tx.Error; err == nil { err = fc(tx) } if err == nil { err = tx.Commit().Error } } panicked = false return }
DB的Transaction方法针对非TxCommitter类型的db.Statement.ConnPool执行db.Begin,之后注册defer针对panicked或者err的执行tx.Rollback(),执行fc之后,判断err为nil的情况下执行tx.Commit(),并将Error赋值为err
func TestInsertInTx(t *testing.T) { err := db.Transaction(func(tx *gorm.DB) error { classes := []model.Class{ { Name: "abc2", }, { Name: "abc2", }, } err := db.Create(&classes).Error if err != nil { return err } uc := []model.UserClass{ { UserId: 1, ClassId: classes[0].ID, }, { UserId: 1, ClassId: classes[1].ID, }, } err2 := db.Create(&uc).Error if err2 != nil { return err2 } return nil }) if err != nil { t.Error(err) } }
gorm的DB提供了Transaction方法,相当于一个事务模板,自动commit或者rollback,它提供了func(tx *gorm.DB) error参数用于自定义事务内的数据库操作。