当前位置:网站首页>gorm事务体验
gorm事务体验
2022-06-28 05:06:00 【.番茄炒蛋】
简介
表
CREATE TABLE `accounts` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL,
`money` decimal(30,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

没有事务
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Account struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"type:varchar(10);not null"`
Money float64 `gorm:"type:decimal(30,2);not null"`
}
func main() {
// 连接对应的数据库
dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "127.0.0.1", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 使用用彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
a := 1 - 1
// 模拟张三给李四转100
account := Account{
ID: 1, Name: "张三", Money: 900}
account1 := Account{
ID: 2, Name: "李四", Money: 1100}
db.Save(&account)
if true {
// 手动制造一个错误
_ = 1 / a
}
db.Save(&account1)
}

在代码中手动制造了一个异常,正常情况下应该转账失败,两个人的余额都还是1000,但是由于没有使用事务,张三已经发生了扣款,但是李四却没有收到钱,这在真实的场景中是绝对不能接受的.
事务
package main
import (
"errors"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Account struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"type:varchar(10);not null"`
Money float64 `gorm:"type:decimal(30,2);not null"`
}
func main() {
// 连接对应的数据库
dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "127.0.0.1", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 使用用彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
db.Transaction(func(tx *gorm.DB) error {
// 模拟张三给李四转100
account := Account{
ID: 1, Name: "张三", Money: 800}
account1 := Account{
ID: 2, Name: "李四", Money: 1100}
tx.Save(&account)
if true {
return errors.New("手动制造一个错误")
}
tx.Save(&account1)
return nil
})
}

使用事务以后就是正常的,出现错误会回滚,返回任何错误都会回滚事务
嵌套事务
package main
import (
"errors"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Account struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"type:varchar(10);not null"`
Money float64 `gorm:"type:decimal(30,2);not null"`
}
func main() {
// 连接对应的数据库
dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "127.0.0.1", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 使用用彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
db.Transaction(func(tx *gorm.DB) error {
// 模拟张三给李四转100
account := Account{
ID: 1, Name: "张三", Money: 800}
account1 := Account{
ID: 2, Name: "李四", Money: 1100}
tx.Save(&account)
tx.Transaction(func(tx *gorm.DB) error {
// 嵌套事务中模仿王五给赵六转100
account2 := Account{
ID: 3, Name: "王五", Money: 900}
account3 := Account{
ID: 4, Name: "赵六", Money: 1100}
tx.Save(account2)
if true {
return errors.New("手动制造一个错误")
}
tx.Save(account3)
return nil
})
tx.Save(&account1)
return nil
})
}

这次错误是发生再嵌套事务中,张三给李四转账是正常完成的,但是王五给赵六转账是出现回滚的
手动事务
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Account struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"type:varchar(10);not null"`
Money float64 `gorm:"type:decimal(30,2);not null"`
}
func main() {
// 连接对应的数据库
dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "127.0.0.1", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 使用用彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
// 模拟张三给李四转100
// 开启事务
tx := db.Begin()
account := Account{
ID: 1, Name: "张三", Money: 700}
account1 := Account{
ID: 2, Name: "李四", Money: 1200}
if result := tx.Save(&account); result.Error != nil {
// 出现错误回滚
tx.Rollback()
}
if result := tx.Save(&account1); result.Error != nil {
// 出现错误回滚
tx.Rollback()
}
// 提交事务
tx.Commit()
}

中间没有出现任何错误,提交事务转账成功.手动事务对error进行判断,如果error不为nil就直接使用tx.Rollback()回滚事务就好了.
SavePoint、RollbackTo
GORM 提供了 SavePoint、Rollbackto 方法,来提供保存点以及回滚至保存点功能
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Account struct {
ID uint `gorm:"primarykey"`
Name string `gorm:"type:varchar(10);not null"`
Money float64 `gorm:"type:decimal(30,2);not null"`
}
func main() {
// 连接对应的数据库
dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "127.0.0.1", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 使用用彩色打印
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
// 模拟张三给李四转100
// 模拟王五给赵六转100
account := Account{
ID: 1, Name: "张三", Money: 600}
account1 := Account{
ID: 2, Name: "李四", Money: 1300}
account2 := Account{
ID: 3, Name: "王五", Money: 900}
account3 := Account{
ID: 4, Name: "赵六", Money: 1100}
tx := db.Begin()
tx.Save(&account)
tx.Save(&account1)
tx.SavePoint("test")
tx.Save(&account2)
tx.Save(&account3)
if true {
// 在这里回滚,只完成张三给李四转账
tx.RollbackTo("test")
}
tx.Commit()
}

使用tx.RollbackTo(“test”)回滚到tx.SavePoint(“test”)之前,只完成张三给李四转账;未完成王五给赵六的转账
注意



再官方文档中,作者秉承着重要的事情说三遍的原则,事务一旦开始就应该使用 tx 处理数据,这一点需要特别注意,如果使用事务之前的db处理事务,出现错误是不会回滚的
边栏推荐
- When excel copies the contents of a row, the columns are separated by the tab "\t"
- Sorting out some topics of modern exchange principle MOOC
- msa.h:没有那个文件或目录
- DPDK 源码测试时性能下降问题
- 吴恩达深度学习测验题:deeplearning.ai-week1-quiz
- Based on the order flow tool, what can we see?
- Opencv实现颜色检测
- Keil C51的Data Overlaying机制导致的函数重入问题
- Extjs图书管理系统源码 智能化图书管理系统源码
- How long will the PMP test results come out? You must know this!
猜你喜欢

?位置怎么写才能输出true

PCR/qPCR研究:Lumiprobe丨dsGreen 用于实时 PCR

Binary sort tree: BST

2022年全国最新消防设施操作员(初级消防设施操作员)模拟题及答案

When excel copies the contents of a row, the columns are separated by the tab "\t"

2022年最新辽宁建筑八大员(标准员)考试试题及答案

Have you finished the examination of level II cost engineer? There are also qualification regulations!

2022 high altitude installation, maintenance and removal examination questions and answers

Extjs library management system source code intelligent library management system source code

Light collector, Yunnan Baiyao!
随机推荐
基于订单流工具,我们能看到什么?
sqlmap工具使用手册
Binary sort tree: BST
改性三磷酸盐研究:Lumiprobe氨基-11-ddUTP
Lumiprobe细胞成像分析:PKH26 细胞膜标记试剂盒
Sorting out some topics of modern exchange principle MOOC
2022年全国最新消防设施操作员(初级消防设施操作员)模拟题及答案
Flexible IP network test tool -- x-launch
cgo+gSoap+onvif学习总结:8、arm平台交叉编译运行及常见问题总结
Mask's miserable and inspirational childhood, who is introverted by campus violence
Dart学习——函数、类
短视频本地生活版块成为热门,如何把握新的风口机遇?
Feign implements path escape through custom annotations
2022年安全员-B证考试题库及答案
Idle interrupt cannot be cleared
CI & CD must be known!
Learning Tai Chi Maker - mqtt Chapter II (VI) mqtt wills
Assembly common instructions
Project practice! Teach you JMeter performance test hand in hand
Severe tire damage: the first rock band in the world to broadcast live on the Internet