锁——《MySQL技术内幕》读书笔记

1、使用锁的目的是什么?
数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性。
2、InnoDB锁
InnoDB使用了表锁和行锁。
InnoDB存储引擎实现了如下两种标准的行级锁:
□ 共享锁(S Lock),允许事务读一行数据。
□ 排他锁(X Lock),允许事务删除或更新一行数据。
共享锁和排他锁的兼容性:(兼容是指对同一条记录锁的兼容性情况)
在这里插入图片描述
InnoDB存储引擎支持多粒度(granular)锁定,这种锁定允许事务在行级上的锁和表级上的锁同时存在。InnoDB支持意向锁,意向锁意味着事务希望在更细粒度(fine granularity)上进行加锁,意向锁即位表级别的锁。
其支持两种意向锁:
□ 意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁
□ 意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁
InnoDB存储引擎中锁的兼容性:
锁——《MySQL技术内幕》读书笔记_第1张图片
3、什么是一致性非锁定读?
是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行DELETE或UPDATE操作,这时读取操作不会因此去等待行上锁的释放。相反地,InnoDB存储引擎会去读取行的一个快照数据
如图:
锁——《MySQL技术内幕》读书笔记_第2张图片
快照数据是指该行的之前版本的数据,该实现是通过undo段来完成。而undo用来在事务中回滚数据,因此快照数据本身是没有额外的开销。读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。
在事务隔离级别READ COMMITTED和REPEATABLE READ(InnoDB存储引擎的默认事务隔离级别)下,InnoDB存储引擎使用非锁定的一致性读。然而,对于快照数据的定义却不相同。在READ COMMITTED事务隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。而在REPEATABLE READ事务隔离级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。READ COMMITTED从数据库理论的角度来看,其违反了事务ACID中的I的特性,即隔离性.
4、什么是一致性锁定读?
在某些情况下,用户需要显式地对数据库读取操作进行加锁以保证数据逻辑的一致性。而这要求数据库支持加锁语句,即使是对于SELECT的只读操作
InnoDB存储引擎对于SELECT语句支持两种一致性的锁定读(locking read)操作:
□ SELECT…FOR UPDATE
□ SELECT…LOCK IN SHARE MODE
SELECT…FOR UPDATE对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁。SELECT…LOCK IN SHARE MODE对读取的行记录加一个S锁,其他事务可以向被锁定的行加S锁,但是如果加X锁,则会被阻塞。
对于一致性非锁定读,即使读取的行已被执行了SELECT…FOR UPDATE,也是可以进行读取的,这和之前讨论的情况一样。此外,SELECT…FOR UPDATE,SELECT…LOCK IN SHAREMODE必须在一个事务中,当事务提交了,锁也就释放了。
5、自增长与锁
在InnoDB存储引擎的内存结构中,对每个含有自增长值的表都有一个自增长计数器(auto-increment counter)。当对含有自增长的计数器的表进行插入操作时,这个计数器会被初始化,执行如下的语句来得到计数器的值:

SELECT MAX(auto_inc_col) FROM t FOR UPDATE

插入操作会依据这个自增长的计数器值加1赋予自增长列。这个实现方式称做AUTO-INCLocking。这种锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事务完成后才释放,而是在完成对自增长值插入的SQL语句后立即释放。
从MySQL 5.1.22版本开始,InnoDB存储引擎中提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了自增长值插入的性能
在InnoDB存储引擎中,自增长值的列必须是索引,同时必须是索引的第一个列。
6、外键与锁
在InnoDB存储引擎中,对于一个外键列,如果没有显式地对这个列加索引,InnoDB存储引擎自动对其加一个索引,因为这样可以避免表锁
7、锁的算法
InnoDB存储引擎有3种行锁的算法,其分别是:
□ Record Lock:单个行记录上的锁
□ Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
□ Next-Key Lock∶Gap Lock+Record Lock,锁定一个范围,并且锁定记录本身
Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。
Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,InnoDB对于行的查询都是采用这种锁定算法。设计目的是解决幻读。
当查询的索引含有唯一属性时,InnoDB存储引擎会对Next-Key Lock进行优化,Next-Key Lock降级为Record Lock仅在查询的列是唯一索引的情况下。对于唯一键值的锁定,Next-Key Lock降级为Record Lock仅存在于查询所有的唯一索引列。若唯一索引由多个列组成,而查询仅是查找多个唯一索引列中的其中一个,那么查询其实是range类型查询,而不是point类型查询,故InnoDB存储引擎依然使用Next-KeyLock进行锁定。
8、解决幻读
在默认的事务隔离级别下,即REPEATABLE READ下,InnoDB存储引擎采用Next-KeyLocking机制来避免Phantom Problem(幻像问题)
InnoDB存储引擎默认的事务隔离级别是REPEATABLE READ,在该隔离级别下,其采用Next-Key Locking的方式来加锁。而在事务隔离级别READ COMMITTED下,其仅采用RecordLock,所以会有幻读问题。
9、数据库怎样解决死锁?
超时回滚
wait-for graph(等待图):InnoDB存储引擎也采用的这种方式。
InnoDB存储引擎并不会回滚大部分的错误异常,但是死锁除外。发现死锁后,InnoDB存储引擎会马上回滚一个事务,这点是需要注意的。因此如果在应用程序中捕获了1213这个错误(发生死锁时,InnoDB抛出这个错误),其实并不需要对其进行回滚。
10、锁升级
锁升级(Lock Escalation)是指将当前锁的粒度降低。举例来说,数据库可以把一个表的1000个行锁升级为一个页锁,或者将页锁升级为表锁。如果在数据库的设计中认为锁是一种稀有资源,而且想避免锁的开销,那数据库中会频繁出现锁升级现象。
InnoDB存储引擎不存在锁升级的问题。因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

你可能感兴趣的:(读书笔记,mysql,数据库)