事务
数据准备,会自动创建
t_dogs
表
Go
type TDog struct {
Name string
}
func tAutoMigrate() {
err := DB.AutoMigrate(&TDog{})
if err != nil {
return
}
}
func main() {
tAutoMigrate()
}
普通事务
开启普通事务可以使用Transaction
方法
WARNING
Transaction
方法中对数据库的操作要使用回调函数中的(tx *gorm.DB)
Go
func normalTransaction() {
err := DB.Transaction(func(tx *gorm.DB) error {
d1 := TDog{Name: "狗哥1号"}
d2 := TDog{Name: "狗哥2号"}
dogs := []TDog{d1, d2}
tx.Model(&TDog{}).Create(&dogs)
return nil
})
if err != nil {
return
}
}
正常情况下会成功创建两条记录,
t_dogs
表结构如下
json
[
{
"name": "狗哥1号"
},
{
"name": "狗哥2号"
}
]
如果
Transaction
函数中返回错误,那么所有操作都不会被执行
Go
func normalErrorTransaction() {
err := DB.Transaction(func(tx *gorm.DB) error {
d3 := TDog{Name: "狗哥3号"}
d4 := TDog{Name: "狗哥4号"}
dogs := []TDog{d3, d4}
tx.Model(&TDog{}).Create(&dogs)
return errors.New("错误")
})
if err != nil {
return
}
}
以上操作,由于
Transaction
函数中返回了error
,所以其中的创建d3、d4
的操作不会成功执行,上述代码执行后t_dogs
表结构如下
json
[
{
"name": "狗哥1号"
},
{
"name": "狗哥2号"
}
]
嵌套事务
在
嵌套事务
中,如果内部事务报错,也不会执行内部的操作
Go
func nestTransaction() {
err := DB.Transaction(func(tx *gorm.DB) error {
d5 := TDog{Name: "狗哥5号"}
tx.Model(&TDog{}).Create(&d5)
err := tx.Transaction(func(tx *gorm.DB) error {
d6 := TDog{Name: "狗哥6号"}
tx.Model(&TDog{}).Create(&d6)
return errors.New("内部事务出错")
})
if err != nil {
// 暂时不处理这个错误 让外部的事务可以顺利执行
//return err
fmt.Printf("内部事务报错 %s\n", err.Error())
}
return nil
})
if err != nil {
return
}
}
以上操作,由于内部的
Transaction
报错,所以不会创建狗哥6号
,而狗哥5号
会被成功创建
如果放开下面的
return
错误,则狗哥6号
和狗哥5号
都不会被创建
Go
if err != nil {
// 暂时不处理这个错误 让外部的事务可以顺利执行
//return err
fmt.Printf("内部事务报错 %s\n", err.Error())
}
手动事务
可以自己开启事务、回滚和提交
手动事务有以下几个方法
Go
// 开启事务
tx := DB.Begin()
// 回滚操作
tx.Rollback()
// 提交,执行全部的操作
tx.Commit()
Commit
示例如下:
Go
func manualTransaction() {
tx := DB.Begin()
d7 := TDog{Name: "狗哥7号"}
d8 := TDog{Name: "狗哥8号"}
tx.Model(&TDog{}).Create(&d7)
tx.Model(&TDog{}).Create(&d8)
tx.Commit()
}
以上代码会创建
狗哥7号
和狗哥8号
,上述代码执行后t_dogs
表结构如下
json
[
{
"name": "狗哥1号"
},
{
"name": "狗哥2号"
},
{
"name": "狗哥5号"
},
{
"name": "狗哥7号"
},
{
"name": "狗哥8号"
}
]
WARNING
执行过
tx.Commit()
方法后,再次执行tx.xxx
操作时,该操作不会执行所以,如果是
手动事务
的情况,所做的操作一定要在tx.Commit
方法执行之前
示例如下:
Go
func manualTransaction2() {
tx := DB.Begin()
d9 := TDog{Name: "狗哥9号"}
d10 := TDog{Name: "狗哥10号"}
tx.Model(&TDog{}).Create(&d9)
tx.Commit()
tx.Model(&TDog{}).Create(&d10)
}
以上操作,在
Commit
之后,再次创建狗哥10号
,该操作不会执行,所以只会创建狗哥9号
,不会创建狗哥10号
,上述代码执行后t_dogs
表结构如下
json
[
{
"name": "狗哥1号"
},
{
"name": "狗哥2号"
},
{
"name": "狗哥5号"
},
{
"name": "狗哥7号"
},
{
"name": "狗哥8号"
},
{
"name": "狗哥9号"
}
]
Rollback
在
Commit
方法执行之前,如果想要回滚之前的操作,可以使用Rollback
方法
Go
func manualTransaction3() {
tx := DB.Begin()
d11 := TDog{Name: "狗哥11号"}
d12 := TDog{Name: "狗哥12号"}
dogs := []TDog{d11, d12}
tx.Create(&dogs)
tx.Rollback()
tx.Commit()
}
TIP
以上代码执行后,不会创建任何数据,因为在
Commit
之前已经回滚(执行Rollback)
方法了,此时再执行Commit
就没用了如果在
Commit
执行之后再去回滚(执行Rollback)
,是不会成功的
记录回滚点
TIP
- 可以使用
tx.SavePoint
方法保存回滚点,然后通过tx.RollbackTo
方法回滚到之前的操作
下面的代码会创建
狗哥13号
,并不会创建狗哥14号
Go
func rollbackPoint() {
tx := DB.Begin()
d13 := TDog{Name: "狗哥13号"}
d14 := TDog{Name: "狗哥14号"}
tx.Model(&TDog{}).Create(&d13)
pointName := "f"
tx.SavePoint(pointName)
tx.Model(&TDog{}).Create(&d14)
tx.RollbackTo(pointName)
tx.Commit()
}
下面的代码会创建
狗哥15号
和狗哥17号
,并不会创建狗哥16号
Go
func rollbackPoint2() {
tx := DB.Begin()
d15 := TDog{Name: "狗哥15号"}
d16 := TDog{Name: "狗哥16号"}
d17 := TDog{Name: "狗哥17号"}
tx.Model(&TDog{}).Create(&d15)
pointName := "f"
tx.SavePoint(pointName)
tx.Model(&TDog{}).Create(&d16)
tx.RollbackTo(pointName)
tx.Model(&TDog{}).Create(&d17)
tx.Commit()
}