InnoDB引擎——6.锁篇

InnoDB引擎——6.锁篇

行级锁神话——行级锁总会增加开销

实际上,只有当实现本身会增加开销时,行级锁才会增加开销,InnoDB存储引擎不需要锁升级,因为一个锁和多个锁的开销是相同的。如何理解?

MyISAM是表锁,数据库中lock和latch都是锁,
latch更轻量,latch又分为mutex(互斥量)和rwlock(读写锁),注意!没有通常死锁检查机制,lock对象是事物,用来锁定数据库对象(表,页,行),lock在提交和回滚后释放,是有死锁机智的。另外latch存在于每个数据结构的对象中,而lock存在于Lock Manager的哈希表中。

两种标准的行级锁:(1)共享锁(S Lock),读锁 (2)排他锁(X Lock),写锁

意向锁(IX)就是将锁定对象分为多个层次,意味着事物更希望在更细粒度上进行加锁。意向锁为表级别的锁:
意向共享锁(IS Lock):事物想获得一张表某几行的共享锁
意向排他锁(IX lock):事物想获得一张表某几行的排他锁

意向锁不会阻塞除全表扫描以外的任何请求,因为InnoDB支持的是行级别的锁。

监控当前事物分析锁问题的三张表:INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS
(待更新)

一致性非锁定读:是指利用多版本控制来读取当前执行时间数据库中行的数据(并不是在每个事物隔离级别都采用非锁定的一致性读),在事物隔离级别为READ COMMITTED(1)和REPEATABLE READ(2)下使用非锁定一致性读,但是在(1)下,读到的是最新的一份快照数据,在(2)下,读到的是事物开始的版本。
对于READ COMMITTED的事物隔离级别而言,违反了隔离性

一致性锁定读:即使对SELECT操作要求更高,有两种方式(1)SELECT …FOR UPDATE 表示对读取的行加一个X锁(2)SELECT…LOCK IN SHARE MODE 补充:这两个必须在一个事物中(因为上述的都是在隔离级别里探讨的),务必加上BEGIN,START TRANSACTION或者SET AUTOCOMMIT=0

自增长与锁:自增长AUTO-INC Locking是一种特殊的表锁机制,为了提高性能,在完成自增长的SQL语句后就释放了,新的机制利用innodb_autoinc_lock_mode来控制自增长模式,默认值为1.(有0,1,2:最开始的0是为了兼容的),在InnoDB存储引擎中,自增长的列必须是索引,同时必须是索引的第一列,不然会报错。

外键和锁:外键主要用于引用完整性的约束检查

锁的算法:
行锁的3种算法:
(1)Record Lock:单个行记录上的锁
(2)Gap Lock:间隙锁,锁定一个范围,不包括记录本身(但是会产生Phantom Problem(幻像问题) ),关闭gap lock 就是隔离级别设为READ COMMITTED
(3)Next-Key Lock :Gap Lock+Record Lock锁定一个范围,并且锁定记录本身。

当查询的索引有唯一性时,InnoDB存储引擎会对Next-key Lock进行优化,将其降级为Record Lock,只锁住索引本身,而不是范围,来提高并发性。如果不唯一(即辅助索引),还会对下一个键值加上gap lock

对于唯一键值的锁定,Next-Key Lock降级为Record Lock仅存在于查询所有的唯一索隐列。若唯一索引由多个列组成,而查询仅是查找多个唯一索引列中的其中一个,那么查询其实是range类型的查询,而不是point类型查询,故InnoDB存储引擎依然使用Next-Key Lock进行锁定

解决Phantom Problem(幻像问题) :在同一事物下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。

锁问题:
(1)脏读:在不同事物下,当前事物可以读到另外事物未提交的数据,简单来说就是可以读到脏数据(不常发生),在一些特殊情景需要READ COMMITTED,比如replication环境中的slave节点,并且在该slave上的查询并不需要特别精确的返回值。

(2)不可重复读:一个事物内多次读取同一个数据集合。在这个事物还没有结束时,另外一个事物也访问了该同一数据集合,并做了一些DML操作,所以两次读到数据不一样。脏读是读到未提交的数据,而不可重复读读到的是已经提交的数据。一般来说,不可重复读的问题是可以接受的。InnoDB存储引擎的默认事物隔离级别是READ REPEATABLE,采用Next-Key Lock(左开右闭)算法,避免了不可重复读的现象。

(3)丢失更新:是另一个锁导致的问题,简单来说就是一个事物的更新操作会被另一个事物的更新操作所覆盖,从而导致数据的不一致。要避免丢失更新发生,需要让事物在这种情况下的操作变成串行化,不是并行操作。

阻塞:阻塞并不是一件坏事,其实是为了确保事物可以并发且可以正常运行。

死锁:
(1)死锁最简单的方式解决方法是超时,一个事物回滚,一个事物继续运行,根据FIFO顺序选择回滚对象,但超时的事物所占权重比较大,就不太合适。

**死锁检测机制:**wati-for graph(等待图)——要求数据库保存以下两种信息,(1)锁的信息链表(2)事物的等待链表

锁升级:Microsoft SQL Server数据库中会有锁升级,粒度降低,认为锁是一种稀有资源,但是InnoDB认为不存在锁升级问题,站在事物的角度认为一个书屋锁住了页中的一个记录还是多个,其开销都是一致的。(采用位图的方式)

小结:需要学会通过一些命令和数据字典来查看事物锁住了哪些资源,不然永远不知道发生了什么,可能只是认为MySQL数据库有时会阻塞而已。

猜你喜欢

转载自blog.csdn.net/u010651249/article/details/83785760