InnoDB实现了两种类型的行锁。数据库
共享锁(S):容许一个事务去读一行,阻止其余事务得到相同的数据集的排他锁。并发
排他锁(X):容许得到排他锁的事务更新数据,可是组织其余事务得到相同数据集的共享锁和排他锁。优化
简单来讲spa
共享锁就是我读的时候,你能够读,可是不能写。3d
排他锁就是我写的时候,你即不能读也不能写。blog
除此以外InnoDB还有两个表锁:索引
意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁事务
意向排他锁(IX):相似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。ip
注意:意向锁是InnoDB自动加的,不须要用户干预。it
对于insert、update、delete,操做
InnoDB会自动给涉及的数据加排他锁;而对于通常的Select语句,InnoDB不会加任何锁(若是没有锁 也就是 select …… from where…… (没有额外加锁后缀)使用MVCC(multiple-version-concurrency-control)是行级锁的变种,它在普通读状况下避免了加锁操做,所以开销更低)可是咱们能够经过如下语句给select加共享锁或排他锁。
共享锁:select * from table_name where ..... lock in share mode
排他锁:select * from table_name where .....for update
下面我将举例说明【注意:须要关闭自动提交事务 set autocommit = 0】
加入共享锁(我读的时候,你能够读,可是不能写)
事务1 |
事务2 |
开启事务 start transaction;
|
开启事务 start transaction; |
查询id=1而且加入共享锁 select * from test where id = 1 lock in share mode;
|
查询id=1而且加入共享锁 select * from test where id = 1 lock in share mode;
|
更新此条纪录,发现锁被占用等待
其余事务退出之后 更新成功
|
也去更新 致使死锁退出
|
|
加入排他锁 这里就不演示了。
具体锁的实现原理
InnoDB行锁是经过给索引项加锁实现的,若是没有索引,InnoDB会经过隐藏的聚簇索引来对记录加锁。
InnoDB这种行锁实现特色意味着:只有经过索引条件检索数据,InnoDB才使用行级锁,不然,InnoDB将使用表锁!
行锁分为三种情形:
Record lock :对索引项加锁,即锁定一条记录。
Gap lock:对索引项之间的‘间隙’、对第一条记录前的间隙或最后一条记录后的间隙加锁,即锁定一个范围的记录,不包含记录自己 (InnoDB使用间隙锁的目的,主要为了防止幻读)
Next-key Lock:锁定一个范围的记录并包含记录自己(上面二者的结合)。
注意:InnoDB默认级别是repeatable-read级别,因此下面说的都是在RR级别中的。
Next-Key Lock是行锁与间隙锁的组合,这样,当InnoDB扫描索引记录的时候,
当咱们用范围条件查询数据,会首先对选中的索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。若是一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的。
下面举例说明
假如数据库有如下3条记录
好比 我要查询
Select * frm test where id>2 for update,
这个时候InnoDB不只会对符合条件的id值为3的记录加锁,也会对id大于3(这些记录并不存在)的“间隙”加锁。
注意:::
当咱们在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这每每会形成严重的锁等待。
所以,尤为是并发插入比较多的应用,
咱们要尽可能优化业务逻辑,尽可能使用相等条件来访问数据,避免使用范围条件。