MySQL innodb的间隙锁定(next-key locking)是为了防止幻读(phantom read),
当MySQL的isolation level设为repeatable read的时候会触发间隙锁定。
这里先讨论 next-key locking 对 select 语句的锁定,不讨论 insert 等操作。
对于select 语句的锁定,总的来说就是:
next-key locking 将自己 查询过程中 所见到的那些行,全部都锁住。
推导一下:
1、如果查询过程中是用的全表扫描,则全表的记录都锁住
2、如果查询过程中是通过索引,则通过索引根据查询条件所匹配的那些记录都锁住,而且此时有新增的记录且该记录能 通过索引根据查询条件所匹配,则也会被锁住
3、如果查询过程中是通过唯一索引,其实情况和 普通索引一样
实例:
通过 name 和 owner 去查找 count:
@Lock(LockModeType.PESSIMISTIC_READ)public long countByNameAndOwner(String name,String owner);
查询语句为:
select count(id) from test where test.name='aaa' and test.owner='bbb' lock in share mode
1、如果查询没有使用到索引,则全表都锁住,不能 insert 、update 、delete
2、如果使用到索引,则将根据索引能查到的记录 锁住,这些记录任何字段不能修改,insert 的记录如果符合索引查出的条件,也将无法进行。
比如:
如果使用的是 name字段索引
将表中所有name为 ‘aaa’ 的记录锁住,如果新增 name为'aaa'的记录,也将无法进行。
如果是 insert 、update 、delete 字段name 不为 'aaa' 的记录,可正常操作。
如果是将 name为'aaa'的记录 的 name 修改为其他字符串,也会被锁住。
如果是使用 name,owner的复合索引,原理也是如上。
最后再来说下 读锁 和 写锁 的区别:
#写锁select * from test where id='1' for update;
#读锁select * from test where id='1' lock in share mode;
这里以 行锁为例进行说明:
写锁:
当记录上没有其他锁时(读锁,写锁),可以加写锁。
写锁会阻止其他锁,但不会阻止 纯粹的 select
insert、update、delete
# *********** 当记录上有写锁时 ***********
#下面语句会被阻止select * from test where id='1' for update;
#下面语句会被阻止select * from test where id='1' lock inshare mode;
#下面语句不会被阻止select * from test where id='1' ;
读锁:
当记录上没有写锁时,可以加读锁
当记录上有其他读锁时,可以再加读锁
记录上存在读锁,则写锁无法再加上,需要等所有的读锁都释放后才行
# *********** 当记录上有读锁时 ***********#下面语句会被阻止select * from test where id='1' for update;
#下面语句不会被阻止select * from test where id='1' lock inshare mode;
#下面语句不会被阻止select * from test where id='1' ;
InnoDB的 insert , update ,delete 的锁
对于insert 语句,新增的记录会关联到唯一索引、主键,在事务提交前,所有与该新增记录 主键相同,唯一索引约束项相同的记录都将被锁住。
对于update、delete语句,和上面类似,where条件将自己 查询过程中 所见到的那些行,全部都锁住。如果是没走索引,该表全部记录锁住。