mysql的锁机制+死锁的产生与避免(以Innodb引擎为例)

一、mysql的锁机制

InnoDB实现了两种类型的行锁:

共享锁(S):允许一个事务去读一行,阻止其他事务获得相同的数据集的排他锁。(我读的时候,你可以读,但是不能写。)

排他锁(X):允许获得排他锁的事务更新数据,但是组织其他事务获得相同数据集的共享锁和排他锁。(我写的时候,你不能读也不能写。)


InnoDB还有两个表锁:

意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁。(要想加S锁,必须先加IS锁)

意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。(要想加X锁,必须先加IX锁)

意向锁是InnoDB自动加的,不需要用户干预。

对于insertupdatedeleteInnoDB会自动给涉及的数据加排他锁(X;对于一般的Select语句,InnoDB不会加任何锁

事务可以通过以下语句给显示加共享锁或排他锁:

共享锁:select * from table_name where .....lock in share mode

排他锁:select * from table_name where .....for update

mysql的锁机制+死锁的产生与避免(以Innodb引擎为例)

利用select ....lock in share mode加入共享锁

mysql的锁机制+死锁的产生与避免(以Innodb引擎为例)

利用select ....for update加入排他锁

mysql的锁机制+死锁的产生与避免(以Innodb引擎为例)


锁的具体实现方式见:https://www.2cto.com/database/201508/429967.html中间部分


二、死锁的产生与避免

死锁:

我们说过MyISAM中是不会产生死锁的,因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么全部等待。

而在InnoDB中,锁是逐步获得的,就造成了死锁的可能。在上面的例子中我们可以看到,当两个事务都需要获得对方持有的锁才能够继续完成事务,导致双方都在等待,产生死锁。发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退,另一个获取锁完成事务。


避免死锁:

有多种方法可以避免死锁,这里只介绍常见的三种:

1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;