当前位置:网站首页>记一次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为数字格式,可以比大小,则按照大小进行排列即可;
边栏推荐
- "NetEase Internship" Weekly Diary (3)
- 【LeetCode每日一题】——654.最大二叉树
- 2022-08-01 mysql/stoonedb slow SQL-Q18 analysis
- 【LeetCode Daily Question】——704. Binary Search
- ofstream,ifstream,fstream read and write files
- Centos7 安装postgresql并开启远程访问
- MySQL8 download, start, configure, verify
- C language inserted into the characters of simple exercises
- 十字光标太小怎么调节、CAD梦想画图算量技巧
- 数据链路层的数据传输
猜你喜欢

【 wheeled odometer 】

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

个人博客系统项目测试

Understand the big model in seconds | 3 steps to get AI to write a summary

Constructor instance method inheritance of typescript38-class (implement)

3. Bean scope and life cycle

手写博客平台~第二天

Redis Subscription and Redis Stream

MySQL优化策略

Typescript31 - any type
随机推荐
How to adjust the cross cursor too small, CAD dream drawing calculation skills
Redis 底层的数据结构
LeetCode Review Diary: 153. Find the Minimum Value in a Rotated Sort Array
The Paddle Open Source Community Quarterly Report is here, everything you want to know is here
HSDC is related to Independent Spanning Tree
6-24 exploit-vnc password cracking
Hash collisions and consistent hashing
AntPathMatcher uses
Project Background Technology Express
Force buckle, 752-open turntable lock
LeetCode brush diary: LCP 03. Machine's adventure
Simple example of libcurl accessing url saved as file
【LeetCode每日一题】——704.二分查找
2023年起,这些地区软考成绩低于45分也能拿证
[ORB_SLAM2] SetPose, UpdatePoseMatrices
AI目标分割能力,无需绿幕即可实现快速视频抠图
The ultra-large-scale industrial practical semantic segmentation dataset PSSL and pre-training model are open source!
LeetCode Brushing Diary: 74. Searching 2D Matrix
Check if IP or port is blocked
[LeetCode Daily Question]——654. The largest binary tree