服务器通信时,SQL语句发生了DeadLock问题,使用事务操作包含相同的update语句导致的deadlock,整了很长一段时间,记录一下。
前提:1:事务A和事务B,在不同线程中,轮询调用使用函数封装的update语句
2:表结构中包含两个字段table_name、user_id,并且将这两个字段设定为唯一索引。
发生错误现象:通过日志以及语句:SHOW ENGINE INNODB STATUS\G,查看发生发生DeadLock现象;
发生问题原因:1.线程A开启事务,并update某一个数据,由于table_name、user_id两字段是唯一索引,因此会开启行级锁。
2.线程B开启事务,同时update这张表,并开启相应行级锁。
3.两个线程开启的事务中,都包含轮询操作。假定第一次线程A锁定行数1,线程B锁定行数2;接着第二次线程A锁定行数2,此时会出现等待,若同时现场线程B尝试更新行数1,则会发生死锁现象;如下两张图:
线程1(轮询语句写在begin和commit之间,线程1更新表raw_key_5后不进行commit,但此时线程2抢夺了资源,并更新了表raw_key_4,当线程2接下去操作raw_key_5时会出现等待,而当线程1再次拿到资源后更新表raw_key_4时就会报deadlock):
线程2:
解决方案:1.将事务执行范围缩小。
2.删除相关唯一索引,将锁范围扩大至表级锁。
3.修改更新语句,将查询条件扩大化,将锁范围扩大至表级锁。