赞
踩
我们在进行互联网应用开发的时候,高并发场景下,很容易遇到死锁的问题,我们从jdbc抛出的死锁异常中,很难看出死锁发生的具体原因,jdbc只是给了一个死锁异常, 但是并没有抛出导致死锁的原因,这是因为mysql本身,发生死锁的时候就没有抛出更多的错误信息。MySQL/InnoDB的加锁分析,对应用开发来说也是比较复杂的,因为 锁这一块的复杂性,很多关于数据库锁的文章,并没有实际的验证,而是似是而非猜测性的,有一些误导。这里是对一个insert和update同一索引数据导致的死锁案例的 分析过程,主要是描述一个解决问题的思路,供大家参考。
X同学在生产上发现了如下的死锁异常,想让我一起排查下,登陆服务器后,看到了类似如下的异常信息:
在分库:[ worker_10~~>jdbc:mysql://hostname:3306/dbname?user=user ],执行SQL:[ UPDATE tablename SET col1 = col1 + 20, modified_date = NOW() WHERE order_id = 'xxx' ], 发生异常:Deadlock found when trying to get lock; try restarting transaction;
我们从日志上看,看不出死锁发生的具体原因,我翻看了发生异常堆栈的代码,类似于我之前做的一个订单台账的死锁问题,因为上次排查的时候,就参阅了不少资料, 有些资料也有一定的误导性,借此我把这次死锁原因复现一下,通过实际的操作来分析一下死锁的原因,并分析一下,如何解决此场景的死锁问题。
我们可以通过show engine innodb status,来查看死锁的日志,看看是否可以看出,是执行哪几个SQL引起的,以下是我找dba拿出的日志,我做了一下脱敏。
2019-07-18 10:03:03 7f16ff826700*** (1) TRANSACTION:TRANSACTION 46497170213, ACTIVE 0 sec starting index readmysql tables in use 1, locked 1LOCK WAIT 3 lock struct(s), heap size 1184, 2 row lock(s)MySQL thread id 118471353, OS thread handle 0x7f1c2fe77700, query id 146140919609 10.240.24.25 dbname updatingUPDATE tablename SET col1 = col1 + 20, modified_date = NOW() WHERE order_id = 'xxx' *** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 2632 page no 5065 n bits 440 index `uniq_table_name_col1` of table `tablename` trx id 46497170213 lock_mode X locks rec but not gap waitingRecord lock, heap no 374*** (2) TRANSACTION:TRANSACTION 46497170214, ACTIVE 0 sec starting index read, thread declared inside InnoDB 5000mysql tables in use 1, locked 13 lock struct(s), heap size 1184, 2 row lock(s)MySQL thread id 118465375, OS thread handle 0x7f16ff826700, query id 146140919617 172.25.213.222 dbname updatingUPDATE tablename SET col1 = col1 + 30, modified_date = NOW() WHERE order_id = 'xxx' *** (2) HOLDS THE LOCK(S):RECORD LOCKS space id 2632 page no 5065 n bits 440 index `uniq_table_name_col1` of table `tablename` trx id 46497170214 lock mode S rec but not gapRecord loc
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。