-
显式锁
# 通过特定的语句进行加锁,我们一般称之为显示加锁
# 显式共享锁
select ... lock in share mode
# 显式排他锁
select ... for update
-
隐式锁
隐式锁是在进行插入操作时,生成的锁;1个事务在进行插入操作时,为了避免其他事务对这条记录进行读或写,导致发生脏读或脏写,会为这个插入操作加上1个隐式锁
插入意向锁也是隐式锁
情景一:对于聚簇索引记录来说,有一个trx_id隐藏列,该隐藏列记录着最后改动该记录的事务id。那么如果在当前事务中新插入一条聚簇索引记录后,该记录的trx_id隐藏列代表的的
就是当前事务的事务id,如果其他事务此时想对该记录添加S锁或者X锁时,首先会看一下该记录的trx_id隐藏列代表的事务是否是当前的活跃事务,如果是的话,那么就帮助当前事务创建
一个X锁(也就是为当前事务创建一个锁结构,is_waiting属性是false),然后自己进入等待状态(也就是为自己也创建一个锁构,is_waiting属性是true)
情景二:对于二级索引记录来说,本身并没有trx_id隐藏列,但是在二级索引页面的Page Header部分有一个PAGE_MAX_TRX_ID属性,该属性代表对该页面做改动的最大的事务id,
如果PAGE_MAX_TRX_ID属性值小于当前最小的活跃事务id,那么说明对该页面做修改的事务都已经提交了,否则就需要在页面中定位到对应的二级索引记录,然后回表找到它对应的
聚簇索引记录,然后再重复情景一的做法
即:一个事务对新插入的记录可以不显式的加锁(生成一个锁结构),但是由于事务id的存在,相当于加了一个隐式锁。别的事务在对这条记录加S锁或者X锁时,由于隐式锁的存在,
会先帮助当前事务生成一个锁结构,然后自己再生成一个锁结构后进入等待状态。隐式锁是一种延迟加锁的机制,从而来减少加锁的数量。
隐式锁在实际内存对象中并不含有这个锁信息。只有当产生锁等待时,隐式锁转化为显式锁
- 案例
# 开启1个连接,开启1个新的事务
begin;
# 执行插入操作
insert INTO student VALUES(34,"周八","二班");
# 开启第2个连接,开启1个新的事务
begin;
# 执行插叙操作,由于上面执行了1个插入操作,第2个事务会为第1个事务生成1个锁结构,第2个事务处于阻塞状态
select * from student lock in share mode;
# 在第1个连接中查看隐式锁
SELECT * FROM performance_schema.data_lock_waits\G;
- 隐式锁的逻辑过程如下:
A. InnoDB的每条记录中都一个隐含的trx_id字段,这个字段存在于聚簇索引的B+Tree中。
B. 在操作一条记录前,首先根据记录中的trx_id检查该事务是否是活动的事务(未提交或回滚)。如果是活
动的事务,首先将 隐式锁 转换为 显式锁 (就是为该事务添加一个锁)。
C. 检查是否有锁冲突,如果有冲突,创建锁,并设置为waiting状态。如果没有冲突不加锁,跳到E。
D. 等待加锁成功,被唤醒,或者超时。
E. 写数据,并将自己的trx_id写入trx_id字段。