当前位置:网站首页>记一次gorm事务及调试解决mysql死锁
记一次gorm事务及调试解决mysql死锁
2022-08-02 02:12:00 【不是住在隔壁的老王】
前言
之前使用mysql和postgresql是通过sqlc包来使用,这一次使用gorm,还是遇到了很多问题,在此记录以下。
版本问题
gorm大版本更新之后,驱动的引入及实际的用法和老版本会有一些区别,特别是事务、锁的使用以及配置项的修改。
新版本gorm数据库链接方式以及包的名称和老版本相比均有改变,如下:
老版本:
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
db, err := gorm.Open("mysql", "root:[email protected](127.0.0.1:3306)/db01?&parseTime=True&loc=Local")
而新版本:
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
})
老版本的配置项通过db.xx的形式修改:
db.LogMode(true)
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
db.SingularTable(true)
而新版本均通过&gorm.Config{}字段进行修改:
db, err = gorm.Open(mysql.Open(dbLink), &gorm.Config{
SkipDefaultTransaction: true, //开启事务
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
forupdate的用法改变:
最开始依旧使用老版本的用法来使用,但是一直不成功,然后使用debug打印sql语句,发现生成的sql语句并没有for update相关操作,再去查找资料,发现老版本写法不生效,更换为新的写法。
老版本:
result := tx.Debug().Set("gorm:query_option", "FOR UPDATE").First(&user1, arg.FromUserID)
新版本:
result = tx.Debug().Clauses(clause.Locking{
Strength: "UPDATE"}).First(&user2, arg.ToUserID)
数据库死锁的排查解决:
在一个类似于转账的场景,为了保证转账的一致性,在相关的接口中使用了事务来保证转账成功,在最后测试同一个账户有人转出,有人转入时出现死锁;
根据网上查询以及一位大佬博文(http://t.csdn.cn/nAzEf)的思路下,在终端还原了死锁场景。
分别开启两个事务,按照顺序进行update操作:在执行第4步即事务2中的第二条操作时,出现死锁。
事务1:
1 update user set collection_coins = collection_coins - 10 where id = 1537973755;
3 update user set collection_coins = collection_coins + 10 where id = 1338725819; 等待获取锁
事务2:
2 update user set collection_coins = collection_coins - 10 where id = 1338725819;
4 update user set collection_coins = collection_coins + 10 where id = 1537973755;

查询相关锁的表,能看到在发生死锁的上一步:
分别运行以下两个语句:
select * from information_schema.innodb_locks;
select * from information_schema.innodb_lock_waits;

运行:
SELECT * FROM information_schema.innodb_trx;
可以看到
可以看到,两个事务均获得了锁,进行了第3个操作时,事务1阻塞,等待事务2释放
锁;如果此时事务2不释放锁,反而执行第4个操作,则会造成事务2请求锁,但此时锁在事务1处,而事务1已经阻塞,无法释放锁,则事务2也会被阻塞,形成死锁。
解决办法则是:
调换4个语句的执行顺序;
如果按照1-4-3-2的顺序来进行则不会造成死锁。
因为在执行1后,事务1获得锁1,此时事务2执行4,事务2请求锁1,此时事务2阻塞;
事务1再执行3,获得锁2;此时事务1执行完毕,commit释放锁1和锁2,事务2获得锁1,语句4执行成功,再执行语句2成功,则不会发生死锁。
换到代码中则是对执行顺序进行排列,利用id为数字格式,可以比大小,则按照大小进行排列即可;
边栏推荐
- The underlying data structure of Redis
- Project Background Technology Express
- The Paddle Open Source Community Quarterly Report is here, everything you want to know is here
- Win Go开发包安装配置、GoLand配置
- Data transfer at the data link layer
- libcurl访问url保存为文件的简单示例
- to-be-read list
- PHP 使用 PHPRedis 与 Predis
- typescript35-class的构造函数
- typescript31-any类型
猜你喜欢

Handwritten Blog Platform ~ Day Two

Ringtone 1161. Maximum In-Layer Elements and

Day115. Shangyitong: Background user management: user lock and unlock, details, authentication list approval

2022-07-30 mysql8执行慢SQL-Q17分析

拼多多借力消博会推动国内农产品品牌升级 看齐国际精品农货

MySQL优化策略

AI目标分割能力,无需绿幕即可实现快速视频抠图

Record the pits where an error occurs when an array is converted to a collection, and try to use an array of packaging types for conversion

AWR分析报告问题求助:SQL如何可以从哪几个方面优化?

【LeetCode每日一题】——103.二叉树的锯齿形层序遍历
随机推荐
Coding Experience Talk
typescript33 - high-level overview of typescript
数据链路层的数据传输
乱七八糟的网站
bool框架::PosInGrid (const简历:关键点kp, int &posX, int诗句)
Multi-Party Threshold Private Set Intersection with Sublinear Communication-2021:解读
LeetCode刷题日记:74. 搜索二维矩阵
[LeetCode Daily Question] - 103. Zigzag Level Order Traversal of Binary Tree
Huawei's 5-year female test engineer resigns: what a painful realization...
『网易实习』周记(二)
HSDC is related to Independent Spanning Tree
2022-07-30 mysql8 executes slow SQL-Q17 analysis
[LeetCode Daily Question]——654. The largest binary tree
Ringtone 1161. Maximum In-Layer Elements and
2022-08-01 安装mysql监控工具phhMyAdmin
【 wheeled odometer 】
项目后台技术Express
雇用WordPress开发人员:4个实用的方法
typescript30-any类型
待读书单列表