MySQL并发控制
锁
确保事务隔离性的方法之一: 要求对数据项以互斥的方式进行访问. 换句话说, 当一个事务访问某个数据项时, 其他任何事务都不能修改该数据项. 实现该需求的最常用的方法: 只允许事务访问当前该事务持有锁(lock)的数据项.
- 共享锁(shared-mode lock)记为S: 如果事务获得了数据项上的共享锁, 则事务可以读但不能写.
- 排他锁(exclusive-mode lock)记为X: 如果事务获得了数据项上的排他锁, 则事务既可读又可写.
- 共享锁排他锁兼容性如下图:
- image
每个事务都要根据对数据项的操作类型进行申请(request)适当的锁. 该事务将请求发送给并发控制管理器. 事务只有在并发控制管理器授予(grant)所需锁后才能继续其操作. 这两种类型(共享锁|排他锁)可以让多个事务读取同一个数据项但是限制同时只能有一个事务进行写操作.
锁的授予必定是在事务申请锁操作与事务的下一个动作的间隔内.
死锁: 产生死锁比产生不一致状态要好, 因为死锁可以通过回滚事务加以解决, 而不一致状态可能引起现实中的问题, 这是数据库系统不能处理的.
锁的授予: 当事务申请对一个数据项加某一类型锁,且没有其他事务在该数据项上加上了与此类型相冲突的锁, 则可以授予锁.
事务饿死(starved): 事务2在数据项上持有共享锁,事务1申请加排他锁. 事务1需要等待事务2释放共享锁. 同时事务3对数据项申请加共享锁, 加锁请求是相容的,则可授权事务3加共享锁. 如果存在一个事务序列, 每个事务都对数据项加共享锁, 导致事务1总是不能在数据项上加排他锁, 事务1永远没有进展.
避免事务饿死: 当事务T申请对数据项加M型锁时, 并发控制管理器授权加锁的条件是:
- 不存在在数据项上持有与M型锁冲突的锁的其他事务;
- 不存在等待对数据项加锁且先于事务T申请加锁的事务.
因此一个加锁请求就不会被其后的加锁申请阻塞.
封锁协议
封锁协议(locking protocol): 规定事务何时对数据进行加锁 解锁. 封锁协议限制了可能的调度数目. 这些调度组成的集合是所有可能的可串行化调度的一个真子集.
两阶段封锁协议(two-phase locking protocol)
此协议用于保证可串行性. 要求事务分两个阶段提出加锁和解锁申请.
- 增长阶段(growing phase): 事务可以获得锁,但不能释放锁.
- 缩减阶段(shrinking phase): 事务可以释放锁, 但不能获得新锁.
最初, 事务处于增长阶段, 事务根据需要获得锁.一旦事务释放了锁,就进入了缩减阶段,并且不能再发出加锁请求.
-
封锁点(lock point): 对于任何事务, 在调度中该事务获得其最后加锁的位置(增长阶段结束点)称为事务的封锁点.可以证明两阶段封锁协议保证冲突可串行化. 这样, 多个事务可以根据它们的封锁点进行排序, 这个顺序就是事务的一个可串行化顺序.
-
严格两阶段封锁协议(strict two-phrase locking protocol): 避免级联回滚. 这个协议除了要求封锁是两阶段之外, 还要事务持有的所有排他锁必须在事务提交后方可释放. 保证未提交事务所写的任何数据在该事务提交之前均以排他方式加锁, 防止其他事务读这些数据.
-
强两阶段封锁协议(rigorous two-phrase locking protocol): 要求事务在提交之前不得释放任何锁(排他锁共享锁). 事务可以按其提交的顺序串行化.
-
多级粒度(granularity)封锁协议: 通过允许各种大小的数据项并定义数据粒度的层次结构, 其中小粒度数据项嵌套在大粒度数据项中来实现.可以类比为树结构.主要针对的表锁与行锁.
-
树中的每个结点都可以加锁. 当事务对一个结点加锁(共享锁或排他锁), 该事务也以同类型的锁隐式的封锁这个结点的全部后代结点.
-
意向锁(intention lock mode): 如果一个结点加上了意向锁, 则意味着将要或已经在树的较低层显式加锁(即以更小的粒度加锁). 在一个结点显式加锁之前, 该结点的全部祖先结点均加上了意向锁. 因此事务不用搜索整棵树就能判定能否成功给一个结点加锁, 效率更高.希望给某个结点加锁的事务必须遍历从根结点到某结点的路径, 在遍历树的过程中, 该事务给各结点加上意向锁.
-
共享型意向锁(intention-shared (IS) mode): 如果一个结点(如表)加上了此锁, 则树的较低层次(比如行)将要或已经加了共享锁.
-
排他型意向锁(intention-exclusive (IX) mode): 如果一个结点(如表)加上了此锁, 则树的较低层次(比如行)将要或已经加了排他锁.
-
意向锁的兼容性如下图所示:
image- 意向锁之间是相互兼容的
- 上图中的排他锁与共享锁针对是表锁.
- 意向锁不会与行级的共享锁排他锁互斥!!!
- 意向锁是由数据引擎自己维护的, 程序员不需要手动去操作.
-
意向锁的意义: 当对表级进行加锁时, 需要遍历整张表, 看是否加有锁. 效率太低. 引入意向锁后, 仅需要检查表上是否加有不相容的意向型锁, 不需要遍历整张表.
-
总结:
-
Innodb
支持多粒度锁, 特定场景下, 行级锁可以和表级锁共存(比如行共享锁,表共享锁) - 意向锁互相兼容. 但除了共享型意向锁与共享锁兼容外, 意向锁会与共享锁 排他锁互斥.
- 共享型意向锁/排他型意向锁是表级锁, 不会和行级的共享锁/排他锁互斥. 只会和表级的共享锁/排他锁互斥.
- 意向锁在保证并发性的前提下, 实现了行锁与表锁共存且满足事务隔离性的需求.
-
-
-
多粒度协议: 要求加锁按自顶向下的顺序, 而锁的释放则按自底向上的顺序.
-
多粒度协议意义: 增强了并发性, 减少了锁开销.
-
网友评论