当前位置:网站首页>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
边栏推荐
- C语言中函数是什么?编程中的函数与数学中的函数区别?理解编程语言中的函数
- Lumiprobe细胞成像分析:PKH26 细胞膜标记试剂盒
- Voltage mode and current mode control of switching power supply
- msa. h: There is no such file or directory
- Unity out ref params
- 改性三磷酸盐研究:Lumiprobe氨基-11-ddUTP
- [JVM series] JVM tuning
- 学习太极创客 — MQTT 第二章(四)ESP8266 保留消息应用
- DPDK 源码测试时性能下降问题
- It is the latest weapon to cross the blockade. It is one of the fastest ladders.
猜你喜欢

Dart learning - functions, classes

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

基于订单流工具,我们能看到什么?

DH parameters of robotics and derivation using MATLAB symbolic operation

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

并发之wait/notify说明

学习太极创客 — MQTT 第二章(六)MQTT 遗嘱

2022年安全员-B证考试题库及答案

The heading angle of sliceplane is the same as that of math Corresponding transformation relation of atan2 (y, x)

大促场景下,如何做好网关高可用防护
随机推荐
Don't roll! How to reproduce a paper with high quality?
Sorting out some topics of modern exchange principle MOOC
[skywalking] learn distributed link tracking skywalking at one go
Standard particle swarm optimization C language program
mysql----where 1=1是什么意思
IP datagram sending and forwarding process
活性染料研究:Lumiprobe AF594 NHS 酯,5-异构体
BioVendor sRAGE抗体解决方案
羧酸研究:Lumiprobe 磺基花青7二羧酸
二级造价工程师考试还没完?还有资格审核规定!
大促场景下,如何做好网关高可用防护
改性三磷酸盐研究:Lumiprobe氨基-11-ddUTP
Light collector, Yunnan Baiyao!
氨基染料研究:Lumiprobe FAM 胺,6-异构体
BioVendor sRAGE蛋白解决方案
Is it enough for the project manager to finish the PMP? no, it isn't!
Object detection with OpenCV
JS text box loses focus to modify width text and symbols
109. 简易聊天室12:实现客户端一对一聊天
Leetcode 88: merge two ordered arrays