【有书共读】《MySQL技术内幕》读书笔记06--锁
lock和latch区别
- latch:闩锁(轻量级锁),要求锁的时间非常短,分为互斥量mutex和读写锁rwlock。目的是保证并发线程操作临界资源的正确性,没有死锁检测的机制
- lock:对象是事务,用来锁定数据库中的对象,表、行、页。lock的对象在事务结束释放,有死锁机制
InnoDB存储引擎中的锁
锁类型
- 共享锁S Lock:允许事务独一行数据,只与S锁兼容
- 排它锁X Lock:允许事务删除或更新一行数据,与任何锁都不兼容
- 意向锁:意向共享锁IS,意向排他锁IX。将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度上进行加锁
一致性非锁定读
- innodb通过行多版本控制的方式MVCC读取当前执行时间数据库的数据,如果当前数据记录有X锁,那么innodb会读取一个快照数据
- READ COMMITTED事务隔离级别支持非锁定的一致性读,快照数据是最新一份
- REPEATABLE READ支持非锁定一致性读,快照为事务开始之前的版本
一致性锁定度
- SELECT...FOR UPDATE:在读取的行记录添加一个X锁
- SELECT..LOCK IN SHARE MODE:对读取的行记录添加一个S锁
自增长与锁
- innodb中的自增长值的列必须是索引,且必须是索引的第一个列,否则MySQL抛出异常。MyISAM没有这个问题
外键和锁
- 外键主要用于引用完整性检查;innodb会自动为外键列添加索引,避免表锁
- 对外键的插入和更新需要查询父表的记录,使用SELECT..LOCK IN SHARE MODE。目的:防止父表在对记录做删除操作S锁,导致子表插入成功,但是父表没有对应的记录
锁的算法
- Record Lock:单行锁
如果innodb表在建立的时候没有设置索引,那么会对主键(聚集索引)进行锁定 - Gap Lock:间隙锁,锁定一个范围,不包含记录本身
- Next-Key Lock:锁定一个范围,包含记录本身
- innodb行查询通用算法。例索引有10,11,13,20,那么索引区间可能为(-∞,10](10,11](11,13](13,20](20,+∞]
- 当查询的索引含有唯一属性时,InnoDB会对Next-Key Lock优化,降级为Record Lock;若唯一索引由多个列组成,而查询仅是查找多个唯一索引列中其中一个,那么查询依然是range类型,使用Next-Key Lock
- 解决Phantom Problem(幻读)
- 概念: 同一事务下,连续执行两次相同的SQL语句可能会导致不同的结果,第二次的SQL语句肯呢个会返回之前不存在的行
- innodb默认的事务隔离级别是REAPEATABLE READ,采用Next-Key Locking避免幻读,因为在查询的同时添加l了范围锁,对范围之内记录不允许修改
锁问题
脏读
- 脏数据:事务对缓冲池中行记录的修改还没有被提交,是由于数据库实例内存和磁盘异步造成的。脏也刷新异步,不影响数据库的可用性
- 脏读:一个事务读到了另一个事务未提交的数据
- 脏读发生的事务隔离级别为READ UNCOMMITTED
不可重复读
- 一个事务内多次读取同一数据集合,在这个事务还没有结束时,另外一个事务也访问该同一数据集合,并且做了一些DML操作。
- 脏读和不可重复读区别:脏读就是读到未提交数据,不可重复读读到的是已经提交的数据。
丢失更新
- 一个事务的更新操作被另一个事务的更新操作所覆盖
阻塞
- 一个事务的锁需要等待另一个事务中的锁释放资源
- innodb_lock_wait_timeout参数用来控制等待的时间
死锁
- 概念:两个或两个以上的事务在执行的过程中,因争夺锁资源而造成的一种互相等待的现象。
- 解决办法
- 超时机制:当两个事务相互等待时,当一个事务等待时间超过设置的阈值,就回滚;通过参数innodb_lock_wait_timeout设置等待时间
- 等待图wait for graph:死锁检测,需要:锁的信息链表,事务等待链表,通过两个连表构造图,若存在回路,则有死锁。采用深度优先算法检测
- 锁升级:将当前锁的粒度降低
- innodb不存在锁升级的问题,因为innodb是根据每个事务访问的每个页对锁进行管理的,采用位图的方式。