当前位置:Gxlcms > 数据库问题 > Mysql并发时经典常见的死锁原因及解决方法

Mysql并发时经典常见的死锁原因及解决方法

时间:2021-07-01 10:21:17 帮助过:21人阅读

> select * from t3 where id in (8,9) for update; +----+--------+------+---------------------+ | id | course | name | ctime | +----+--------+------+---------------------+ | 8 | WA | f | 2016-03-02 11:36:30 | | 9 | JX | f | 2016-03-01 11:36:30 | +----+--------+------+---------------------+ rows in set (0.04 sec) Session2: select * from t3 where id in (10,8,5) for update; 锁等待中…… 其实这个时候id=10这条记录没有被锁住的,但id=5的记录已经被锁住了,锁的等待在id=8的这里。 不信请看 Session3: mysql> select * from t3 where id=5 for update; 锁等待中 Session4: mysql> select * from t3 where id=10 for update; +----+--------+------+---------------------+ | id | course | name | ctime | +----+--------+------+---------------------+ | 10 | JB | g | 2016-03-10 11:45:05 | +----+--------+------+---------------------+ row in set (0.00 sec) 在其它session中id=5是加不了锁的,但是id=10是可以加上锁的。

案例2

在开发中,经常会做这类的判断需求:根据字段值查询(有索引),如果不存在,则插入;否则更新。

以id为主键为例,目前还没有id=22的行

Session1:

select * from t3 where id=22 for update;

Empty set (0.00 sec)

 

session2:

select * from t3 where id=23  for update;

Empty set (0.00 sec)

 

Session1:

insert into t3 values(22,ac,a,now());

锁等待中……

 

Session2:

insert into t3 values(23,bc,b,now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

当对存在的行进行锁的时候(主键),mysql就只有行锁。

当对未存在的行进行锁的时候(即使条件为主键),mysql是会锁住一段范围(有gap锁)

 

 

锁住的范围为:

(无穷小或小于表中锁住id的最大值,无穷大或大于表中锁住id的最小值)

 

如:如果表中目前有已有的id为(11 , 12)

那么就锁住(12,无穷大)

如果表中目前已有的id为(11 , 30)

那么就锁住(11,30)

 

对于这种死锁的解决办法是:

insert into t3(xx,xx) on duplicate key update `xx`=‘XX‘;

 

用mysql特有的语法来解决此问题。因为insert语句对于主键来说,插入的行不管有没有存在,都会只有行锁

案例3

直接上情景:

mysql> select * from t3 where id=9 for update;

+----+--------+------+---------------------+

| id | course | name | ctime               |

+----+--------+------+---------------------+

|  9 | JX     | f    | 2016-03-01 11:36:30 |

+----+--------+------+---------------------+
row in set (0.00 sec)

 

Session2:

mysql> select * from t3 where id<20 for update;

锁等待中

 

Session1:

mysql> insert into t3 values(7,ae,a,now());

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

这个跟案例一其它是差不多的情况,只是session1不按常理出牌了,

Session2在等待Session1的id=9的锁,session2又持了1到8的锁(注意9到19的范围并没有被session2锁住),最后,session1在插入新行时又得等待session2,故死锁发生了。

 

这种一般是在业务需求中基本不会出现,因为你锁住了id=9,却又想插入id=7的行,这就有点跳了,当然肯定也有解决的方法,那就是重理业务需求,避免这样的写法。

 

转:https://www.cnblogs.com/zejin2008/p/5262751.html 

 

附记,推荐两篇好文章

案例4:

http://hedengcheng.com/?p=844

 

MySQL 加锁处理分析:

http://hedengcheng.com/?p=771

 

Mysql并发时经典常见的死锁原因及解决方法

标签:业务   values   情况   根据   最大   避免   mysql   页面锁   页面   

人气教程排行