报错详情
Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
The error may involve com.iss.cms.fdrb.common.dao.entity.InterfaceQueue.updateInterfaceQueue-Inline
The error occurred while setting parameters
SQL: update t_fdrb_interface_queue t set t.send_status = ?, t.update_time = ? where tenant_id = ? and biz_code= ? and biz_id = ? and send_status in (1,3)
Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:267)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73)
at org.mybatis.spring.SqlSessionTemplate
MySql锁类型的介绍
上面是MySql锁表的问题报错日志,今天记录一下解决方案。
- 行级锁在使用的时候并不是直接锁掉这行表记录,而是锁索引
- 如果一条Sql用到了主键索引的话,mysql会锁住这条记录主键索引
- 如果一条Sql用到了非主键索引,mysql会先锁住非主键索引,然后再锁定主键索引
原理
mysql的两情况的锁,排它锁与共享锁。
- 排它锁是事务T对数据A加上排他锁,只能允许事务T读取和修改数据A,别的事务没有办法进行读取与修改的操作处理,所以叫做排他锁,是互斥的
- 共享锁是事务T对数据A加上共享锁,其他事务只能再对数据A加上共享锁,而不能进行排它锁的操作,别的事务也可以加上共享锁。是不会进行互斥的
一般造成死锁的原因是因为两个事务添加了锁的时候没有及时进行释放锁资源,等到第二个事务要添加排他锁的时候,发现已经被锁了,从而导致的环路等待,构成死锁
问题的排查过程
日志定位可以找到具体的表是什么,然后定位这
从表里面可以发现进行更新的时候,没有用到索引,而是使用两个非索引,类似聚合索引的方式进行更新的处理。
问题的解决方案
针对这种情况,需要进行调整,先查询出来这一条记录,然后根据主键来进行更新的操作即可。
调整前的sql
update t_fdrb_interface_queue${tableNo} t set
t.send_status = #{sendStatus},
t.update_time = #{updateTime}
where tenant_id = #{tenantId} and biz_code= #{bizCode} and biz_id = #{bizId} and send_status in (1,3)
调整后的sql
第一步:查询
select
t.biz_code as bizCode,
t.biz_id as bizId,
t.send_status as sendStatus,
t.create_time as createTime,
t.update_time as updateTime,
t.send_num as sendNum,
t.send_Lang as sendLang,
t.id as id
from t_fdrb_interface_queue${tableNo} t
where t.tenant_id = #{tenantId} and t.biz_code= #{bizCode} and biz_id = #{bizId} and send_status in (1,3)
第二步:更新
update t_fdrb_interface_queue${tableNo} t set
t.send_status = #{sendStatus},
t.update_time = #{updateTime}
where id= #{id}
这里备注一下,后续在操作更新的操作时,要使用索引进行更新,避免死锁的情况