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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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()
}
}