当前位置:网站首页>记一次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为数字格式,可以比大小,则按照大小进行排列即可;
边栏推荐
- Speed up your programs with bitwise operations
- 3. Bean scope and life cycle
- Fundamentals of Cryptography: X.690 and Corresponding BER CER DER Encodings
- Personal blog system project test
- Constructor instance method of typescript36-class
- NIO‘s Sword(牛客多校赛)
- Redis 底层的数据结构
- Handwriting a blogging platform ~ the first day
- A good book for newcomers to the workplace
- Constructor instance method inheritance of typescript38-class (implement)
猜你喜欢
typescript34-class的基本使用
Handwritten Blog Platform ~ Day Two
typeof in typescript32-ts
volatile原理解析
AI目标分割能力,无需绿幕即可实现快速视频抠图
Analysis of the status quo of digital transformation of manufacturing enterprises
6-24 exploit-vnc password cracking
MySQL8 下载、启动、配置、验证
MySQL optimization strategy
oracle query scan full table and walk index
随机推荐
typescript32-ts中的typeof
volatile原理解析
AI目标分割能力,无需绿幕即可实现快速视频抠图
Hiring a WordPress Developer: 4 Practical Ways
AOF重写
Software testing Interface automation testing Pytest framework encapsulates requests library Encapsulates unified request and multiple base path processing Interface association encapsulation Test cas
Constructor instance method inheritance of typescript38-class (implement)
ofstream,ifstream,fstream read and write files
Multi-Party Threshold Private Set Intersection with Sublinear Communication-2021:解读
The Paddle Open Source Community Quarterly Report is here, everything you want to know is here
『网易实习』周记(三)
AntPathMatcher使用
"NetEase Internship" Weekly Diary (2)
[ORB_SLAM2] SetPose, UpdatePoseMatrices
C language inserted into the characters of simple exercises
云和恩墨:让商业数据库时代的价值在openGauss生态上持续繁荣
手写一个博客平台~第三天
垃圾回收器CMS和G1
openGauss切换后state状态显示不对
AWR分析报告问题求助:SQL如何可以从哪几个方面优化?