You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

264 lines
5.4 KiB

package gormExample
import (
"errors"
"gorm.io/gorm"
"log"
)
func TXDemo() {
// 初始化测试数据
if err := DB.AutoMigrate(&Author{}); err != nil {
log.Fatalln(err)
}
var a1, a2 Author
a1.Name = "库里"
a2.Name = "莫兰特"
a1.Points = 11600
a2.Points = 200
if err := DB.Create([]*Author{&a1, &a2}).Error; err != nil {
log.Fatalln(err)
}
// 事务操作
// a1 赠送 a2 2000 积分
p := 2000
// 开始事务
tx := DB.Begin()
// 有时需要考虑数据库是否支持事务的情景
if tx.Error != nil {
log.Fatalln(tx.Error)
}
// 执行赠送操作
a1.Points -= p
a2.Points += p
// 1执行SQL可能导致的错误
if err := tx.Save(&a1).Error; err != nil {
tx.Rollback()
return
}
if err := tx.Save(&a2).Error; err != nil {
// 回滚事务
tx.Rollback()
return
}
// 2业务逻辑可能导致的错误
// 要求author的积分不能为负数
if a1.Points < 0 || a2.Points < 0 {
log.Println("a1.Points < 0 || a2.Points < 0")
// 回滚事务
if err := tx.Rollback().Error; err != nil {
log.Fatalln(err)
}
}
// 提交事务
if err := tx.Commit().Error; err != nil {
log.Fatalln(err)
}
// 决定回滚还是提交,集中的处理错误风格
//if err1 != nil || err2 != nil {
// tx.Rollback()
//} else {
// tx.Commit()
//}
}
func TXCallback() {
// 初始化测试数据
if err := DB.AutoMigrate(&Author{}); err != nil {
log.Fatalln(err)
}
var a1, a2 Author
a1.Name = "库里"
a2.Name = "莫兰特"
a1.Points = 1600
a2.Points = 200
if err := DB.Create([]*Author{&a1, &a2}).Error; err != nil {
log.Fatalln(err)
}
log.Println(a1.ID, a2.ID)
// 实现事务
if err := DB.Transaction(func(tx *gorm.DB) error {
// a1 赠送 a2 2000 积分
p := 200
// 执行赠送操作
a1.Points -= p
a2.Points += p
// 1执行SQL可能导致的错误
if err := tx.Save(&a1).Error; err != nil {
return err
}
if err := tx.Save(&a2).Error; err != nil {
return err
}
// 2业务逻辑可能导致的错误
// 要求author的积分不能为负数
if a1.Points < 0 || a2.Points < 0 {
return errors.New("a1.Points < 0 || a2.Points < 0")
}
// nil 的返回,会导致事务提交
return nil
}); err != nil {
// 返回错误,为了后续的业务逻辑处理
// 为了通知我们,事务成功还是失败
// 返回错误,不影响事务的提交和回滚
log.Println(err)
}
}
func TXNested() {
// 初始化测试数据
if err := DB.AutoMigrate(&Author{}); err != nil {
log.Fatalln(err)
}
var a1, a2, a3 Author
a1.Name = "库里"
a2.Name = "莫兰特"
a3.Name = "欧文"
a1.Points = 1600
a2.Points = 200
a3.Points = 4000
if err := DB.Create([]*Author{&a1, &a2, &a3}).Error; err != nil {
log.Fatalln(err)
}
log.Println(a1.ID, a2.ID, a3.ID)
// 实现事务
if err := DB.Transaction(func(tx *gorm.DB) error {
// a1 赠送 a2 2000 积分
p := 20000
// 执行赠送操作
// a2 多了积分
a2.Points += p
if err := tx.Save(&a2).Error; err != nil {
return err
}
// a1 赠送,使用嵌套事务完成
errA1 := tx.Transaction(func(tx *gorm.DB) error {
a1.Points -= p
// 1执行SQL可能导致的错误
if err := tx.Save(&a1).Error; err != nil {
return err
}
if a1.Points < 0 {
return errors.New("a1.Points < 0")
}
// 没有错误成功
return nil
})
// a1 发送失败才需要a3
if errA1 != nil {
// a3 赠送,使用嵌套事务完成
errA3 := DB.Transaction(func(tx *gorm.DB) error {
a3.Points -= p
if err := tx.Save(&a3).Error; err != nil {
return err
}
if a3.Points < 0 {
return errors.New("a3.Points < 0")
}
return nil
})
// a3 同样失败
if errA3 != nil {
return errors.New("a1 and a3 all send points failed")
}
}
// nil 的返回,会导致事务提交
return nil
}); err != nil {
// 返回错误,为了后续的业务逻辑处理
// 为了通知我们,事务成功还是失败
// 返回错误,不影响事务的提交和回滚
log.Println(err)
}
}
func TXSavePoint() {
// 初始化测试数据
if err := DB.AutoMigrate(&Author{}); err != nil {
log.Fatalln(err)
}
var a1, a2, a3 Author
a1.Name = "库里"
a2.Name = "莫兰特"
a3.Name = "欧文"
a1.Points = 1600
a2.Points = 200
a3.Points = 4000
if err := DB.Create([]*Author{&a1, &a2, &a3}).Error; err != nil {
log.Fatalln(err)
}
log.Println(a1.ID, a2.ID, a3.ID)
// 事务操作
// a1 赠送 a2 2000 积分
p := 20000
// 开始事务
tx := DB.Begin()
// 有时需要考虑数据库是否支持事务的情景
if tx.Error != nil {
log.Fatalln(tx.Error)
}
// 执行赠送操作
// a2 得到积分
a2.Points += p
// 1执行SQL可能导致的错误
if err := tx.Save(&a2).Error; err != nil {
tx.Rollback()
return
}
// 逻辑记录发送points是否成功
var flagSend bool
// a1 先给 a2 send
// 设置一个 savepoint
tx.SavePoint("beforeA1")
a1.Points -= p
if err := tx.Save(&a1).Error; err != nil || a1.Points < 0 {
// 回滚到 beforeA1
tx.RollbackTo("beforeA1")
// a3 to a2
tx.SavePoint("beforeA3")
a3.Points -= p
if err := tx.Save(&a3).Error; err != nil || a3.Points < 0 {
// 回滚到 beforeA3
tx.RollbackTo("beforeA3")
} else {
flagSend = true
}
} else {
flagSend = true
}
// 判定发送是否成功
if flagSend {
// 提交事务
if err := tx.Commit().Error; err != nil {
log.Fatalln(err)
}
} else {
// 回滚事务
tx.Rollback()
}
}