当前位置:网站首页>Gorm transaction experience
Gorm transaction experience
2022-06-28 05:12:00 【. fried eggs with tomatoes】
brief introduction
gorm Transaction Chinese document
surface
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;

No transaction
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() {
// Connect to the corresponding database
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( The target of log output , Prefix and what the log contains —— translator's note )
logger.Config{
SlowThreshold: time.Second, // slow SQL threshold
LogLevel: logger.Info, // The level of logging
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound( Record not found ) error
Colorful: true, // Use color printing
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
a := 1 - 1
// Simulate Zhang San to Li sizhuan 100
account := Account{
ID: 1, Name: " Zhang San ", Money: 900}
account1 := Account{
ID: 2, Name: " Li Si ", Money: 1100}
db.Save(&account)
if true {
// Manually make an error
_ = 1 / a
}
db.Save(&account1)
}

An exception was manually created in the code , Under normal circumstances, the transfer should fail , The balance of both men is still 1000, But since no transaction is used , Zhang San has already deducted money , But Li Si didn't receive the money , This is absolutely unacceptable in the real scene .
Business
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() {
// Connect to the corresponding database
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( The target of log output , Prefix and what the log contains —— translator's note )
logger.Config{
SlowThreshold: time.Second, // slow SQL threshold
LogLevel: logger.Info, // The level of logging
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound( Record not found ) error
Colorful: true, // Use color printing
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
db.Transaction(func(tx *gorm.DB) error {
// Simulate Zhang San to Li sizhuan 100
account := Account{
ID: 1, Name: " Zhang San ", Money: 800}
account1 := Account{
ID: 2, Name: " Li Si ", Money: 1100}
tx.Save(&account)
if true {
return errors.New(" Manually make an error ")
}
tx.Save(&account1)
return nil
})
}

It is normal to use transactions , Errors will roll back , Returning any error rolls back the transaction
Nested transactions
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() {
// Connect to the corresponding database
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( The target of log output , Prefix and what the log contains —— translator's note )
logger.Config{
SlowThreshold: time.Second, // slow SQL threshold
LogLevel: logger.Info, // The level of logging
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound( Record not found ) error
Colorful: true, // Use color printing
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
db.Transaction(func(tx *gorm.DB) error {
// Simulate Zhang San to Li sizhuan 100
account := Account{
ID: 1, Name: " Zhang San ", Money: 800}
account1 := Account{
ID: 2, Name: " Li Si ", Money: 1100}
tx.Save(&account)
tx.Transaction(func(tx *gorm.DB) error {
// In nested transactions, imitate Wang Wu to Zhao liuzhuan 100
account2 := Account{
ID: 3, Name: " Wang Wu ", Money: 900}
account3 := Account{
ID: 4, Name: " Zhao Liu ", Money: 1100}
tx.Save(account2)
if true {
return errors.New(" Manually make an error ")
}
tx.Save(account3)
return nil
})
tx.Save(&account1)
return nil
})
}

This error occurs in nested transactions , Zhang San's transfer to Li Si was normally completed , But Wang Wu's transfer to Zhao Liu was rolled back
Manual transactions
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() {
// Connect to the corresponding database
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( The target of log output , Prefix and what the log contains —— translator's note )
logger.Config{
SlowThreshold: time.Second, // slow SQL threshold
LogLevel: logger.Info, // The level of logging
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound( Record not found ) error
Colorful: true, // Use color printing
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
// Simulate Zhang San to Li sizhuan 100
// Open transaction
tx := db.Begin()
account := Account{
ID: 1, Name: " Zhang San ", Money: 700}
account1 := Account{
ID: 2, Name: " Li Si ", Money: 1200}
if result := tx.Save(&account); result.Error != nil {
// Error rollback
tx.Rollback()
}
if result := tx.Save(&account1); result.Error != nil {
// Error rollback
tx.Rollback()
}
// Commit transaction
tx.Commit()
}

There were no errors in the process , Transaction transfer submitted successfully . Manual transaction pair error Judge , If error Not for nil Just use it tx.Rollback() Just roll back the transaction .
SavePoint、RollbackTo
GORM Provides SavePoint、Rollbackto Method , To provide savepoint and rollback to savepoint
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() {
// Connect to the corresponding database
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( The target of log output , Prefix and what the log contains —— translator's note )
logger.Config{
SlowThreshold: time.Second, // slow SQL threshold
LogLevel: logger.Info, // The level of logging
IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound( Record not found ) error
Colorful: true, // Use color printing
},
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err)
}
// Simulate Zhang San to Li sizhuan 100
// Imitate Wang Wu to Zhao liuzhuan 100
account := Account{
ID: 1, Name: " Zhang San ", Money: 600}
account1 := Account{
ID: 2, Name: " Li Si ", Money: 1300}
account2 := Account{
ID: 3, Name: " Wang Wu ", Money: 900}
account3 := Account{
ID: 4, Name: " Zhao Liu ", Money: 1100}
tx := db.Begin()
tx.Save(&account)
tx.Save(&account1)
tx.SavePoint("test")
tx.Save(&account2)
tx.Save(&account3)
if true {
// Rollback here , Only transfer money from Zhang San to Li Si
tx.RollbackTo("test")
}
tx.Commit()
}

Use tx.RollbackTo(“test”) Roll back to tx.SavePoint(“test”) Before , Only transfer money from Zhang San to Li Si ; The transfer from Wang Wu to Zhao Liu has not been completed
Be careful



In the official documents , The author adheres to the principle of saying important things three times , Once a transaction starts, you should use tx Processing data , This needs special attention , If you use the pre transaction db Deal with affairs , If an error occurs, it will not be rolled back
边栏推荐
- mysql----where 1=1是什么意思
- DH parameters of robotics and derivation using MATLAB symbolic operation
- Blocking, non blocking, IO multiplexing select\poll\epoll
- 【JVM系列】JVM调优
- How to do a good job of gateway high availability protection in the big promotion scenario
- Qcom LCD commissioning
- 开关电源电压型与电流型控制
- 【SkyWalking】一口气学完分布式链路追踪SkyWalking
- 深度强化学习笔记
- metaRTC5.0 API编程指南(一)
猜你喜欢

Based on the order flow tool, what can we see?

Feign通过自定义注解实现路径的转义

Don't roll! How to reproduce a paper with high quality?

交流电和直流电的区别是什么?

Light collector, Yunnan Baiyao!

如何学习可编程逻辑控制器(PLC)?

学习太极创客 — MQTT 第二章(四)ESP8266 保留消息应用

Learning Tai Chi Maker - mqtt Chapter 2 (V) heartbeat mechanism

2022年低压电工考题及答案

2022新版nft源码中国元宇宙数字藏品艺术品交易平台源码
随机推荐
学习太极创客 — MQTT 第二章(六)MQTT 遗嘱
Simple usage of GSAP
刘海屏手机在部分页面通过[[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom得到底部安全区高度为0问题
2022高处安装、维护、拆除考试题及答案
Cgo+gsoap+onvif learning summary: 8. Summary of arm platform cross compilation operation and common problems
改性三磷酸盐研究:Lumiprobe氨基-11-ddUTP
几百行代码实现一个脚本解释器
Opencv实现颜色检测
Study on chemical properties and technology of biovendor rage ELISA Kit
氨基染料研究:Lumiprobe FAM 胺,6-异构体
穿越封锁的最新利器,速度最快梯没有之一。
摄像头基础知识
吴恩达深度学习测验题:deeplearning.ai-week1-quiz
无线传感器网络学习笔记(一)
Light collector, Yunnan Baiyao!
cgo+gSoap+onvif学习总结:8、arm平台交叉编译运行及常见问题总结
Redis 的 最新windows 版本 5.0.14
2022新版nft源码中国元宇宙数字藏品艺术品交易平台源码
Learning Tai Chi Maker - mqtt Chapter II (VI) mqtt wills
Opencv实现目标检测