登录
注册
写文章
发现
工具
Update引发的数据库死锁
_3t3lfz KEKfID
编辑文章
Update引发的数据库死锁
asfx站长
2023.10.08 21:26:56
阅读
545
最近,生产环境发生了一次数据库死锁异常,经排查,是由于<span style="color:red">Update</span>修改表时where条件只用上了普通索引,导致执行时先获取的是行级锁,然后又因为并发请求时前后2次请求加锁顺序不一致,产生了数据库死锁。 数据库错误提示如下: ``` Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction ; Lock wait timeout exceeded; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction ``` ####产生死锁的真实案例回放: 1. 线程A先获取到k1的redis锁,修改表A的数据,条件是:where aa = 'xxx'(普通索引) 2. 此时线程B获取到k2的redis锁,并想要在表A新增一条数据 3. 这时线程A想要获取到k2的redis锁,由于线程B已占有该锁,导致线程A被阻塞等待(无法提交数据库事务) 4. 因为线程A的数据库事务(无主键索引或唯一索引去修改表A)未提交,导致线程B新增A表数据的操作发生死锁,直到等待锁超时异常 5. 此时线程B因异常错误退出,释放了redis锁,线程A才拿到redis锁并提交了数据库事务 ####解决方案: 1.修改A表数据的where条件增加主键或唯一索引(<span style="color:red">建议这条必须做,避免发生不必要的死锁</span>) 2.修改锁的获取顺序使其保持一致,例如线程A先获取到k1的redis锁,再立刻去获取k2的redis锁,然后才去修改表A的数据
我的主页
退出