? 一方面要最大程度地利用数据库的并发访问,另一方面还要确保每个用户能以一致的方式读取和修改数据
? 1.锁是数据库系统区别于文件系统的一个关键特性
? 2.锁机制用于管理对共享资源的并发访问
? 3.数据库使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性
? 1.latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短,长了性能会非常差
? 2.在InnoDB中,latch分为mutex(互斥量)和rwlock(读写锁)
? 3.其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制
? 1.lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行
? 2.一般lock的对象仅在事务commit或rollback后进行释放(注意不同事务隔离级别不同)
? 3.有死锁机制
? ①共享锁(S Lock)允许事务读一行数据
? ②排他锁(X Lock)允许事务删除或更新一行数据
? -锁兼容(Lock Compatible):事务T1 已获得行r的S锁、T2可立即获得行r的共享锁,因为读取并不会改变行r的数据
? -锁不兼容:T3想获得行r的排他锁,则其必须等待事务T1、T2释放行r上的共享锁
?
? ①这种锁定允许事务在行级上的锁和表级上的锁同时存在,由意向锁实现
? ②意向锁(Intention Lock),将锁定的对象分为多个层次,意向锁意味着事务希望在更细粒度(fine granularity)上进行加锁,将上锁的对象看成一棵树,那么对最下层的对象上锁,也就是对最细粒度的对象进行上锁,那么首先对粗粒度的对象上锁
? ③InnoDB其意向锁即为表级别的锁,设计目的是为了在一个事务中揭示下一行将被请求的所类型
? (1)意向共享锁(IS Lock),事务想要获得一张表中某几行的共享锁
? (2)意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁
?
? 一致性的非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过多行版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据
?
? ①之所以称为非锁定读,因为不需要等待访问的行上X锁的释放,而会去读取行的一个快照数据,而快照数据的实现是通过undo段来完成,而undo用来在事务中回滚数据,因此快照数据本身没有额外开销,而且读取快照数据是不需要上锁的
? ②一个行记录可能不只有一个快照数据,一般称这种技术为行多版本技术。由此带来的并发控制,称之为多版本并发控制(Multi Version Concurrency Control,MVCC)
? ③不同事务隔离级别下的非锁定的一致性读,READ COMMITED,读被锁定行最新一份快照数据;REPEATABLE READ,读事务开始时的行数据版本
?
? InnoDB存储引擎对于SELECT语句支持两种一致性的锁定读(locking read)操作:
? ①SELECT...FOR UPDATE
? 对读取的行记录加一个X锁,其他事务不能对已锁定的行加上任何锁
? ②SELECT... LOCK IN SHARE MODE
? 对读取的行记录即一个S锁,其他事务可向被锁定的行加S锁,但如果加X锁,则会被阻塞
? ③此外以上两种操作必须在一个事务中,但事务提交了,锁也就释放了,因此在使用上述语句SELECT锁定语句时,务必加上BEGIN,START TRANSCATION或者SET AUTOCOMMIT=0
?
? 一种主键方式,在InnoDB内存结构中,对每个含有自增长值的表都有一个自增长计算器(auto-increment counter),当进行插入操作时,这个计数器会被初始化
? ①AUTO-INC Locking ,插入操作会依据这个自增长的计数器值加1赋予自增长列,一种特殊的表锁机制,为提高插入性能,锁不是在事务完成后释放,而是在完成对自增长插入的SQL语句后立即释放
? 缺点:1)对有自增长值得并发插入性能较差,事务必须等待前一个插入的完成
? 2)对于INSERT...SELECT的大数据量的插入会影响插入的性能,因为另一个事务中的插入会被阻塞
? ②插入类型
?
? ③在InnoDB中,自增长的列必须是索引,同时必须是索引的第一个列
?
? ①外键主要用于引用完整性的约束检查检查
? ②对于外键值得插入或更新,首先需要查询父表中得记录,即SELECT父表。但是对于父表的SELECT操作,不使用一致性非锁定读的方式,因为这样会发生数据不一致的问题,因此这时使用SELECT...LOCK SHARE MODE方式
? ①Record Lock:单个记录上的锁
? ②Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
? ③Next-Key Lock: Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。其设计目的就是为了解决Phantom Problem ?,它锁定的是一个范围,是谓词锁(predict lock)的一种改进,当单查询的索引含有唯一属性时,InnoDB存储引擎会优化N-K L降级为Record Lock,即锁住索引本身
?
?
? ④Gap Lock的作用是为了组织多个事务将记录插入到同一范围内,而这会导致Phantom Problem问题的产生,用户可显示关闭Gap Lock
? (1)将事务的隔离级别设置为READ COMMITED
? (2)将参数innodb_locks_unsafe_for_binlog设置为1
? 但这样的设置破坏了事务的隔离性,而且对于replication,可能会导致主从数据不一致,性能也不会比READ REPEATABLE好
? ①在默认隔离级别下,即REPEATABLE READ下,InnoDB采用Next-Key Lock机制来避免Phantom Problem?(幻像问题)
? ②Phantom Problem(幻像问题)它是指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行
?
?
? 因为事务隔离性的要求,锁只会带来三种问题,如果可以这三种情况的发生,那件不会产生并发异常
? ①与脏页区分开:
? 1)脏页是在缓冲池中已经被修改的页,但还没有刷新的磁盘中,即数据库实例内存中的页和磁盘中的页的数据是不一致的,当然在刷新磁盘之前,日志都已经被写入到了重做日志中
? 而且脏页并不影响数据的一致性(两者最终会达到一致,脏页都会刷回到磁盘),并且脏页的刷新是异步的,不影响数据库的可用性,因此可能带来性能的提高
? 2)而所谓脏数据是指事务对缓冲池中行记录的修改,并且没有被提交(commit)
? 如果读到了脏数据,即一个事务可以读到另一个事务中未提交的数据,则显然违反了数据库的隔离性
? ②发生条件
? 在生产环境中不常发生,发生条件所需事务隔离级别为READ UNCOMMITTED,而绝大部分数据库至少设置成READ COMMITED,InnoDB默认为READ REPEATABLE
? ①不可重复读是指在一个事务内多次读取同一数据集合,在这个事务还没有结束时,另外一个事务也访问该同一数据集合,并做了一些DML操作。
? 因此在第一个事务中的两次读数据之间,由于第二个事务的修改,导致第一个事务两次读到的数据可能不一致的情况,这种情况称为不可重复读
? ②不可重复读和脏读的区别:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据,但是其违反了数据库事务一致性的要求
? ③很多数据库厂商(Oracle、Microsoft SQL Server)默认隔离级别READ COMMITTED下允许不可重复读现象
? ④在InnoDB中,用Next-Key Lock来避免不可重复读的问题(MySQL官方定义为Phantom Problem),即幻像问题。在NKL下,对于索引的扫描,不仅是锁住扫描到的索引,而且还锁住这些索引覆盖的范围(gap)。因此在这个范围内的插入都是不允许的,这样就避免了另外的事务的数据插入带来的不可重复读问题。
? 因此InnoDB隔离级别默认使用READ REPEATABLE,采用Next-Key Lock算法
? 丢失更新是另一个锁导致的问题,简单来说就是一个事务的更新操作会被另一个事务的更新操作所覆盖,从而导致数据的不一致,在当前数据库的任何隔离级别下,都不会导致数据库理论意义上的丢失更新问题
? 但在生产应用中还有另一个逻辑意义上的丢失更新问题(银行转账问题)
?
? ①如何避免?
? 需让事务在这种情况下的操作变成串行化,而不是并行的操作
? 示例:
? 因为不同锁的兼容性关系,在有些时刻一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源,阻塞不是坏是,其是为了确保事务可以并发且正常地运行
? ①innodb_lock_wait_timeout用来控制等待的时间(默认50秒)
? ②innodb_rollback_on_timeout用来设定是否在等待超时时对进行中的事务进行回滚操作(默认OFF,代表不回滚),参数innodb_lock_wait_timeout是动态的
? 死锁是指两个或以上的事务在执行过程中,因为争夺资源而造成的一种互相等待的现象
? (1)最简单的一种方法超时,即当两个事务互相等待时,当一个等待时间超过设置的某一阈值,其中一个事务进行回滚,另一个等待的事务就能继续进行,用innodb_lock_wait_timeout设置超时时间
? (2)采用wait-for graph(等待图)方式来进行死锁检测
? 它要求数据库保存:1)锁的信息链表 2)事务等待链表
? 而在途中,事务T1指向T2边的定义为:
? 1)事务T1等待事务T2所占用的资源
? 2)事务T1最终等待T2所占用的资源,也就是事物之间等待相同的资源,而事务T1发生在事务T2后面
? 通过上述链表构造出一张图,若这个图中存在回路,就代表存在死锁,因此资源间相互发生等待
? 若存在死锁,通常来说InnoDB存储引擎选择回滚undo量最小的事务
? wait-for graph检测通常采用深度优先的算法实现,1.2之前,都是采用递归方式实现,1.2后,将递归用非递归的方式实现,从而提高InnoDB存储引擎的性能
?
? 死锁概率与以下几点因素有关:
? ①系统中事务的数量(n),数量越多发生死锁的概率越大
? ②每个事务操作的数量(r),每个事务操作的数量越多,发生死锁的概率越大
? ③操作数据的集合(R),越小则发生死锁的概率越大
? 锁升级是指当前锁的粒度降低,例如,数据库可以把一个表的1000个行级锁升级为页锁,或者将页锁升级为表锁
? InnoDB存储引擎不存在锁升级的问题,因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式,因此不管一个事务锁住页中一个记录还是多个记录,其开销都是一致的
--------------摘自《MySQL技术内幕:InnoDB存储引擎》
原文:https://www.cnblogs.com/Seraphire-yili/p/13921626.html