lock与latch
在数据库中lock与latch分别指不同的所。
- latch:可分为互斥量(mutex)和读写锁(rwlock),目的在于保证数据库内部的结构中共享资源并发时能够正确操作,其对象主要是内存中的各种数据库的数据结构如LRU等。
- lock:用来锁定数据库中的对象,如表、页、行。一般lock的对象在事物的begin transaction开始上锁,到commit或rollback释放锁。lock还会提供死锁机制,而latch则是正常的代码上的锁。
Innodb中锁
Innodb实现了两种标准的行级锁。
- 共享锁(S Lock):允许事物读一行数据(读锁).
- 排他锁(X Lock):允许事物删除或更新一行数据(写锁).
共享锁可以看成是读锁,排他锁可以当作写锁。因此S锁与S锁可兼容,X锁不可兼容。
为了能在不同粒度上进行加锁,Innodb支持意向锁(Intention Lock),其将锁定的对象分为多个层次(表、页和记录),其表示事物希望在更细的粒度上进行加锁。
innodb支持表级别的意向锁
- 意向共享锁(IS Lock):事物想要获得一张表中某几行的共享锁。
- 意向排它锁(IX Lock):事物想要获得一张表中某几行的排他锁。
行级锁与表级锁的兼容性
IS | IX | S | X | |
---|---|---|---|---|
IS | 兼容 | 兼容 | 兼容 | 不兼容 |
IX | 兼容 | 兼容 | 不兼容 | 不兼容 |
S | 兼容 | 不兼容 | 兼容 | 不兼容 |
X | 不兼容 | 不兼容 | 兼容 | 不兼容 |
show engine innodb status
可查看数据库当前锁请求information_schema
下的innodb_trx
、innodb_locks
和innodb_lock_waits
三张表记录当前数据库的锁和事物相关信息。
一致性非锁定读
- 原理:MVCC通过行多版本控制的方式读取数据,从而实现读取数据不需要上锁(即使被上了X锁),可以直接读取数据快照。
- 实现方式:快照数据是指该行的之前的数据版本,通过undo段实现。
- innodb默认是非锁定读,RC和RR两种级别均采用该方式,但是不同的隔离级别读取的数据快照版本也不一样。
- RC下读取总是被锁定行的最新一份快照数据(可能出现不可重复读的问题)
- RR下读取的总是事物开始时的行数据版本.
一致性锁定读
显示对数据库读取操作进行加锁以保证数据逻辑的一致性。
select ... for update //加X锁
select ... lock in share mode //加S锁
自增长实现
- 每个含有自增长值的表都有一个自增长计数器(auto-increment counter),当要使用时执行
select max(col) from t for update;
- 这种实现方式的锁为AUTO-INC Locking,一种特殊的锁机制,其在完成自增值插入的SQL后将立即释放锁。然而对于insert的并发会造成阻塞。
- innodb新的解决方案,
innodb_autoinc_lock_mode
控制自增长模式。 innodb_autoinc_lock_mode = 0
使用AUTO-INC Lockinginnodb_autoinc_lock_mode = 1
(默认模式)对于插入之前就能确定插入行数的使用互斥量去对内存中的计数器进行累加操作,而不能确定行数的(insert...select 或load data)则还是采用AUTO-INC Locking.innodb_autoinc_lock_mode = 2
都使用互斥量对内存计数器做累加。
外键与锁
- innodb对于外键将自动创建一个索引。
- 对与外键的插入或更新将先用锁定读方式读取父表,给父表加了一把S锁。为了防止父表中的数据修改导致外键约束错误。
锁算法
InnoDB的三种行级锁
- Record Lock:单个行记录上的锁
- Gap Lock:间隙锁,锁定一个范围,不包括记录本身。作用在于阻止多个事物将记录插入到同一范围内。
- Next-Key Lock:Gap+Record Lock,锁定一个范围和记录本身。对行的查询都是采用该锁。当该锁作用与唯一索引上时将降级为Record Lock
死锁
死锁指两个或以上的事物在执行过程中,因争夺锁资源而造成的一种互相等待的现象。
解决方法:
- 超时回滚,通过对超时的事物进行回滚的操作。
- wait-for graph(等待图),主动的检测死锁机制,每个事物在请求锁发生等待时都会判断是否存在回路,若存在则选择回滚undo量最小的事物。采用深度有限算法实现。