本篇介绍有关数据库锁相关的知识,关于数据库事务及隔离级别参见《数据库事务ACID特性及隔离级别》这篇文。


乐观锁

乐观锁最常用的实现方式是用数据版本(Version)记录机制。数据版本即为数据增加一个版本标识,一般通过在数据库表中增加一个数字类型的 “version” 字段实现。读取数据时将version字段值一同读出,数据每更新一次,对version值加1,提交更新时将数据库表对应记录的当前version值与已取出的version值进行比对,如果数据库表当前version值与已取出的version值相等,则可以更新,否则认为是过期数据。


通常在实际项目中涉及金钱类的可能会使用这种乐观锁。


举例:



1、数据库表三个字段,分别是id、value、version


select id,value,version from table1 where id = #{id}


2、每次更新表中的value字段时为了防止发生冲突,需要这样操作


update table1
 
 
set value=2,version=version+1
 
 
where id=#{id} and version=#{version}

悲观锁



悲观锁认为在操作数据时会出现数据冲突,每次都要通过获取锁才能对相同数据进行操作,所以悲观锁需要耗费较多的时间。共享锁 和 排它锁


1、锁的粒度


数据库使用express版本 数据库version_排它锁



InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。行锁可能因为未使用索引而升级为表锁,所以除了检查索引是否创建的同时,也需要通过explain执行计划查询索引是否被实际使用。

 


2、读写锁


数据库使用express版本 数据库version_意向锁_02

3、意向锁(Intention Locks)


为了实现多粒度锁机制,协调 行级读写锁 和 表级读写锁 (也就是不同粒度)之间的关系。意向锁是一种允许 行锁 与 表锁


意向锁分为两种:

意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁)


-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。


SELECT column FROM table1 ... LOCK IN SHARE MODE;

意向排它锁(intention exclusive lock, IX):事务有意向对表中的某些行加排它锁(X锁)


-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。


SELECT column FROM table1 ... FOR UPDATE;

意向锁不会与行级的 共享/排它锁 互斥。


数据库使用express版本 数据库version_数据_03


1) InnoDB 支持多粒度锁,特定场景下,行级锁 可以与 表级锁 共存。


2) 意向锁之间互不排斥,但除了 IS 与 S 兼容外,意向锁会与 共享锁 / 排它锁 互斥。


3) IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。


4) 意向锁在保证并发性的前提下,实现了行锁和表锁共存且满足事务隔离性的要求。

4、记录锁(Record Locks)


记录锁是在索引记录上的锁。例如,SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;


5、间隙锁(Gap Locks)


间隙锁(gap)是索引记录之间上的锁,或者说第一个索引记录之前或最后一个索引记录之后的间隔上的锁。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE; 阻止其他事务插入 t.c1 = 15

6、NK锁(Next-Key Locks)


NK锁是记录锁和间隙锁的组合,锁定一个范围,并且锁定记录本身。对查询范围进行加锁,在另一个事务执行插入操作时是不被运行的,从而避免了幻读。用于解决幻读问题。

InnoDB默认的事务隔离级别是Repeatable Read,此时InnoDB使用NK锁进行搜索和索引扫描,防止产生幻读。

7、插入意向锁(Insert Intention Locks)


插入意向锁是在插入一条记录行前,由 INSERT 操作产生的一种间隙锁。该锁用以表示插入意向,当多个事务在同一区间(gap)插入位置不同的多条数据时,事务之间不需要互相等待。

插入意向锁本质上可以看成是一个间隙锁(Gap Lock)。

普通的Gap Lock 不允许 在(上一条记录,本记录)范围内插入数据

插入意向锁Gap Lock 允许 在(上一条记录,本记录)范围内插入数据

插入意向锁的作用是为了提高并发插入的性能, 多个事务 同时写入 不同数据 至同一索引范围(区间)内不需要等待其他事务完成,不会发生锁等待。

InnoDB 在 Repeatable Read 的事务隔离级别下,使用插入意向锁来控制和解决并发插入。

8、自增锁(AUTO-INC Locks)


自增锁是由插入到具有AUTO_INCREMENT列的表中的事务所采用的特殊表级锁。 在最简单的情况下,如果一个事务正在向表中插入值,任何其他事务必须等待,以便这个事务获得连续的主键值。