MySQL死锁

死锁产生的条件:

(1)互斥条件:一个资源在同一时刻只能被一个进程占有

(2)请求与保持:一个进程因请求资源发生阻塞时,对当前已占有的资源不释放

(3)不可剥夺:对于进程已获得的资源,在使用完成之前,不允许其他进程剥夺

(4)循环等待:循环等待资源的环形状态

myisam是deadlock free的,myisam要么一次性获得全部的锁,要么等待,不会产生死锁。

innodb的锁是逐步获得的,如果两个事务在执行过程中,都需要等待对方持有的排他锁,此时,就会产生死锁

innodb存储引擎有自动探测死锁的机制

1.innodb自动检测死锁

  (1)产生死锁之后,innodb回很快检测到,并回滚一个代价较小的事务,通过计算事务插入的行等,判断事务的大小

  (2)InnoDB_lock_wait_timeout参数,当等待的时间超过该值时,自动回滚

      注意:该参数不仅可以解决死锁问题,当并发访问量较高时,避免大量事务因获取不到锁尔挂起,造成数据库资源浪费

  (3)wait for graph 算法

      该算法将事务看成节点,资源就是各个事务占用的锁,当事务1需要等待事务2的锁时,就生成一条有向边从1指向2,最后行成一个有向图。

      如果该有向图有环,意味着死锁,每当加锁请求无法立即满足需要并进入等待时,wait-for graph算法都会被触发。

2.死锁的示例

(1)两个事务操作不同表的相同的记录行

  解决:在必须锁定多个资源的情况下,约定不同事务中,必须按照相同的顺序锁定资源。

事务A 事务B

update user set name = 'duan' where id = 1

(id是主键,给该行加排他锁)

delete from order where  id = 1

(想要再给当前行加排他锁时,发现事务B已在当前行上加了排他锁,阻塞)

delete from order where  id = 1

(id是主键,给该行加排他锁)

update user set name = 'duan' where id = 1

(想要再给当前行加排他锁时,发现事务A已在当前行上加了排他锁,阻塞)

(2)

  update的执行过程分两步,读取当前记录,更新当前记录

  解决:更新锁

    当执行update时,数据库系统给当前记录加上一个更新锁(更新锁和共享锁可以兼容,但是,一个资源最多只能拥有一把更新锁)

    在读取数据完毕之后,将更新锁上升为排他锁

    由于一个资源只能拥有一把更新锁,所以,只能一个事务结束之后, 另一个事务开始执行

事务A 事务B

select * from user where id = 2;

(给当前记录将更新锁)

 
 

update user set name = 'duan' where id = 2;

(事务B企图在ID=2的行上加排他锁,但是,该记录已经有共享锁,由于排他锁不能和任何锁兼容,此时,inndb会加上一个意向排他锁)

update user set name = 'duanjiaping' where id = 2;

(事务A此时企图将加在ID=2的记录上的共享锁上升为排他锁,但是,发现该记录上有事务B加上的意向排他锁,一个记录上只能有一个意向排他锁,因此,阻塞)

 
   

  

(3)

事务A 事务B
update user set name = 'd' where id =1  
  update user set name = 'd' where id =2
update user set name = 'j' where id = 2  
  update user set name = 'j' where id = 1

(4)

可以使用不同的索引锁定不同的行

不能使用不同的索引锁定相同的行

事务A 事务B
update user set name = 'd' where id = 3  
 

update set name ='d' where stuNo = 2

(stuNo列也建立了索引,且与事务A锁定的是统一记录)

(5)

执行update时,如果where筛选条件制定的记录存在,则,只会锁定当前行,否则,行锁上升为表锁

原文地址:https://www.cnblogs.com/duanjiapingjy/p/9415753.html