您的位置:首页 > 其它

趁热来一发——关于避免死锁时测试结果颠覆三观不得不思考虫生这件小事

2017-11-15 00:00 260 查看
navicat是个碧池。

情景:在一个事务里写上了有in 有for update的语句,被提醒可能发生死锁,于是去做一波死锁情况的测试来考虑对策

基本知识:当两个session都需要对方的资源而舍不得自己的资源的时候,就死锁了,所以理论上我这里可能死锁的情况是(省略了begin和commit语句,假设表为A,id为主键,index为有索引的键,normal为普通的字段):

Session1:select * from A where id in (2,3) for update

Session2:select * from A where id in (1,2,3) for update

Session1:update A set normal='test' where id =1

DEADLOCK

意思就是会话一锁了2,3,会话二锁了1,遇到2,3的时候等待,会话一再想更新1,就懵逼了

————————————————————————————————————————————————————————

然鹅,我就遇到了如下的不合理情况:

一、事务级别为RR,使用终端mycli为会话一,navicat为会话二,上述语句能正常在mycli报错,但当然在两表互锁后,用会话一先更新id为2的数据,再更新id为1的数据居然直接成功了,navicat也通过了阻塞出来了数据

二、理论上index字段也是行级锁,也会死锁,于是

Session1:select * from A where index in (2,3) for update

Session2:select * from A where index in (1,2,3) for update

Session1:update A set normal='test' where index=1

居然顺利通过了,navicat中也在持续阻塞,两个事务都能正常手动提交

三、操作normal时是正常的表锁的情况,但explain的时候很懵逼

explain update A set normal='test'

发现type=index,key=PRIMARY,但rows是全表的条数

————————————————————————————————————————————————————————

解决过程,其实主要还是几条查询语句切来切去来看情况,简单记录下语句

show processlist —— 查看当前的连接状态,主要看State字段

select * from information_schema.INNODB_TRX —— 查看当前事务和状态

show status like '%lock%' —— 查看当前锁情况

show OPEN TABLES where In_use > 0; —— 查看当前被锁的表

————————————————————————————————————————————————————————

结论:

1、马丹的,其实是会话二,即navicat的事务抛出了死锁异常,然后navicat并没有提醒出来。。。

2、使用in语句查询有索引的字段的时候并不一定是走的索引,优化器会根据情况选择更快的方法,这里explain一下便可知道index in (1,2) 当时的type=ALL,因此也是进行了表锁,在把数据加了很多是的type=range后,如愿发生了死锁

3、还真没查到。。。explain delete也是正常的type=ALL,可能是update的特殊
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: