当前位置: 首页 > 科技观察

奇怪的数据库“死锁”,问题出在哪里?_0

时间:2023-03-16 15:45:28 科技观察

程序死锁的问题很难调试。看进程栈,看各个线程和锁的情况,对照代码检查。数据库死锁的问题就更难了。你看不到数据库堆栈,也看不到数据库线程和锁。根据代码进行检查更加困难。前段时间和朋友讨论了一个“疑似”数据库死锁问题,最终通过实验和排查找到了问题所在。场景如下:同一张表,高并发事务,先在事务中插入一条记录,然后更新这条记录:如果更新的是唯一索引,则异常;如果更新的是自增主键,也不例外;画外音:还没被“死锁”的描述搞糊涂,到底是死锁问题,阻塞问题,还是其他异常,我单独说。而且,据我朋友说,还可以复现:开始交易;插入一条记录;睡眠5秒;修改插入的记录;并发时稳定重现。据朋友描述,离线打开多个MySQL客户端测试并发模式,结果比较出乎意料。第一步:数据准备createtablet(idint(20)primarykeyAUTO_INCREMENT,cellvarchar(20)unique)engine=innodb;新建表:存储引擎为innodb,MySQL版本为5.6;id字段,自增主键;单元格字段,唯一索引;开始事务;insertintot(单元格)值(11111111111);insertintot(单元格)值(22222222222);insertintot(单元格)值(33333333333);提交;插入一些测试数据。Step2:session参数设置事务的隔离级别,事务自动提交等参数设置不当会影响实验结果。问了朋友,事务的隔离级别是RR(可重复读)。setsessionautocommit=0;setsessiontransactionisolationlevelrepeatableread;每个会话开始后:关闭自动提交;将事务隔离级别设置为RR;showsessionvariableslike"autocommit";showsessionvariableslike"tx_isolation";如果您不放心,可以用以上两种说法进行核对确认。第三步:多个终端会话模拟并发交易。如上图所示,使用SecureCRT打开两个窗口:窗口A,先启动事务,插入记录;B窗口,再次开始事务,同样插入记录;A窗口,修改插入的记录;B窗口也修改了插入的记录;一个奇怪的现象出现了,如果并发事务的update语句:更新条件是cell,就会出现异常;更新条件为id,一切正常;插入不冲突的记录是合理的,然后修改这条记录,行锁应该不会冲突吧?唯一索引和主键索引怎么会有区别呢?有关系吗?是死锁还是其他原因?请帮忙分析分析,问题出在哪里?专栏作者《58神剑》原创稿件,转载请联系原作者】点此查看该作者更多好文