共享锁与排它锁都是行级锁
ID | NAME |
---|---|
1 | HU |
T1 假如对 数据
中的 ID 1
上共享锁, 那么T2事务可以立即获取 ID 1
的共享锁, 因为读取并不会改变 ID 1
的数据, 称这种情况叫做**锁兼容**
若其他事务T3想获取ID 1
的排它锁,则必须等待T1,T2的共享锁释放, 这种情况叫琐不兼容
排它锁/共享锁兼容表
- | 共享锁 | 排它锁 |
---|---|---|
共享锁 | 兼容 | 不兼容 |
排它锁 | 不兼容 | 不兼容 |
排他锁对任何锁都不兼容, 共享锁只对共享锁兼容, 兼容指的是对一行记录
InnoDB存储引擎支持多粒度锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在, 称为意向锁
其意向锁即为表级锁.设计的目的主要为了一个事物中揭示下一行将被请求的锁类型,支持两种意向锁:
👆🏻上面引入的绘图中红色的是意向锁的加锁流程,
假如我们要对User表上的记录上X锁, 那么需分别对, 数据库A, User表,页上意向锁(IX), 最后才能对记录上X锁, 其中任何一个部分导致等待, 那么该操作需要等待粗粒度锁完成
意向锁不会阻塞全表扫描/表级锁其他的任何请求, 设计目的就是为了在一个事物中揭示下一行将要请求锁的类型
举例
ID | NAME |
---|---|
6962683844633821184 | HU |
6962689962995089408 | XUE |
set AutoCommit = 0;
SELECT * FROM T1 WHERE id = 6962689962995089401 FOR UPDATE
**事务1 **对T1表ID 6962689962995089401
加排它锁, 并且不提交事务
lock tables T1 WRITE;
**事务2 **获取T1表的表锁, 进入等待, 引入 **意向锁不会阻塞全表扫描/表级锁其他的任何请求**
set AutoCommit = 0;
SELECT * FROM t_qrcode_info WHERE id = 6962689962995089408 FOR UPDATE
事务3 对ID 6962689962995089408
加排它锁, 不需要等待, **意向锁不会阻塞全表扫描/表级锁其他的任何请求**
**, 查询的数据不同, 不会堵塞, 但是如果也去查询 ****ID **6962689962995089401
就会进入堵塞
一致性非锁定读是指InnoDB存储引擎通过多版本控制的方式来读取当前执行时间数据库中行的数据.
如果读取的行正在执行DELETE或UPDATE操作, 这是读取操作不会因此去等待行上的锁释放, 而是会读取行的快照数据.
称之为 非锁定读 是因为不需要等待行上的X锁
快照数据是指该行之前版本的数据, 该实现是通过undo段来完成, 而undo用来在实务中回滚数据, 因此快照数据本身是没有额外的开销的.
此外, 读取快照数据是不需要上锁的, 因为没有事务需要对历史的数据进行修改操作的
在InnoDB默认设置下, 这是默认的读取方式, 即读取不会占用和等待行上的锁. 在不同隔离级别下, 不是都采用一致性非锁定读, 即使都使用非锁定读, 但是对于快照的定义也各不相同
隔离级别 | 一致性非锁定读定义 |
---|---|
Read Commited | 总是读取锁定行最新的快照数据 |
Repetable Read | 总是读取事务开启时行的数据版本 |
在某些业务下, 需要显示的对读取操作加锁, 保证数据逻辑的一致性. InnoDB支持两种一致性锁定读操作:
- 对应一致性非锁定读即时加了FOR UPDATE, 也是可以进行读取操作, 和之前讨论的情况一样, 读取快照数据
- 对于两种加锁方式, 都必须在事务中, 当事务提交, 锁也就释放了
锁算法有三种
锁定一行就是记录锁
)