序
本文主要研究一下gorm的Transaction
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参数用于自定义事务内的数据库操作。
网友评论