01
02.
互斥访问数据
分成两种:
事务控制器的作用
共享锁之间可以相容,但是任何一个共享锁和每一种排他锁都是互斥的
申请共享锁的命令和申请排他锁命令
如果存在排他锁,必须等待
只要对一个数据项,有读写方法,就必须要申请锁(无论是什么锁),最后一次访问,关掉锁
例子:T1转账 ,T2显示金额 和 A+B账户的总体金额
另一个例子:
这个例子显示的事A+B=250
解释说明,在事务控制器在授予事务锁的时候,这个期间其他事务不能运行:
事务申请锁,事务控制器授予锁
锁导致的死锁的问题:
锁的优缺点:
总体上说锁的使用还是优点多于缺点
锁带来的事务优先级,如果两个锁之间不相容的话,先获得其中一个锁的事务,优先级更高
这个和之前的指令优先级类似
封锁协议:
封锁协议中调度的合法问题
锁的授予:
T2有数据项A的共享锁,T1申请这个数据项A的排他锁,T2会等待
T3申请这个数据项A的共享锁,T2会直接申请到数据项A
如果T2完成操作,还有T3还在数据项A,如果在此期间,还有T4申请数据项A 的共享锁
T1需要等待T3,T4都要操作完成后,才可以访问。也许要等好久才可以。这回叫做饿死
处理饿死的方法:
T2是符合第二种的,事务控制器不会让T3申请数据项A的共享锁成功
T1在运行期间,根本不会让T2区申请数据项A的排他锁的,这个是第一种
两阶段封锁协议
T3,T4是两阶段
T1,T2不是两阶段
加锁的最后一步指令,可以认为是封锁点,锁可以更加直接的反应指令之间按是否冲突,这也就是看出来指令冲突可串行—调度可串行
两阶段只能保证数据访问顺序,间接保证程序按照想要的顺序执行,不能保证死锁,死锁是两个互斥资源都加锁都还相互访问,这系列个动作导致的
两阶段只能保证数据访问顺序,间接保证程序按照想要的顺序执行,不能保证级联回滚,这个和提交有关
严格两阶段封锁协议----------------- 申请的锁只能是排他锁 提交事务后才可以释放锁:
这样就能实现另一个事务的对一个数据项A读方法,只能在已经操作数据项A的事务提交之后,才可以运行------无级联------------排他锁在起作用
强两阶段封锁协议----------------- 提交事务后才可以释放锁:
此时共享锁没有作用,不能控制T8中的写方法和T9的读方法执行的顺序,从而保证结果
锁升级和锁降级
但是升级操作有条件:
两阶段封锁协议+锁转换 ----------------冲突可串行化的调度
两阶段封锁协议+锁转换 +(排他锁直到事务结束释放)=强两阶段封锁协议+锁转换-------------调度串行无级联
强两阶段封锁协议+锁升级的实现:
封锁(申请锁)的实现:
例子:
锁管理器操作:
图的协议:
树形协议,只用排他锁
有向无环图:
可以使用DFS,找出是否存在环:从某个顶点v 0出发,进行DFS,若存在一条从顶点到已访问顶点的回边(即遍历到同一个点两次),则有向图中存在环。
父节点-----子节点
T10
B—E,D D----G
T11
D—H
T12
B—E
T13
D—H
保证不产生死锁--------冲突可串行
改进保证事务的可恢复性:
Ti执行了一些没有提交的数据的读操作,这样,在这个数据项最后的写操作所在的事务,会记录Ti存在依赖,这个事务没有提交,Ti不能提交
优缺点
死锁的处理:
死锁预防:
01.第一种
变形:
例子:树形协议
02.第二种
比较时间戳
时间戳比较年轻的等待
时间戳比较年轻的抢占
锁超时:
死锁检测:
用等待图
例子:
检测算法如何工作的:
死锁恢复
01.
02.
03.
多粒度
例子:
解释:和树形协议不一样,多粒度是有层次的结构,树形协议都是独立的数据项
父节点显式上锁,属于这个父节点的子节点也会隐式上锁(同一种锁): 父控制子
实现的过程:
其他事务对隐形加锁的子节点进行上锁时候,子结点要进行路径遍历,路径中有不兼容的锁(与申请的锁类型不同)类型,就拒绝
扩展: 子结点的锁类型也应该和父节点一样 (子控制父)
一行 = 一个数据项A 子结点如果上锁,那么父结点 只能上一样的锁, 否则就会出现父结点允许而子结点不允许的情况发生,这个和父结点锁的意义不符合
表是由行组成的,当我们向某个表加锁时,一方面需要检查该锁的申请是否与原有的表级锁相容;另一方面,还要检查该锁是否与表中的每一行上的锁相容。比如一个事务要在一个表上加 S 锁,如果表中的一行已被另外的事务加了 X 锁,那么该锁的申请也应被阻塞。
例子:
根结点想要上锁,如果其中的子结点有已经上锁的情况,就可能出现冲突,要遍历根以下的所有结点查看锁的类型是不是一样,所以根结点这个时候上锁很浪费时间
方法:
意向锁:
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。如:对表中的任一行加锁时,必须先对它所在的表加意向锁,然后再对该行加锁。这样一来,事务对表加锁时,就不再需要检查表中
每行记录的锁标志位了,系统效率得以大大提高。
例如:
一个结点的加s锁或者x锁的时候:
结点本身的所有祖先结点都加上意向锁,
结点的子结点都要显式加锁(s锁或者x锁)
这里说的是父结点就可以不用搜索全部子结点,直接加锁:
过程:
解释:
行级锁(Row-Level Locking):
行级锁是指在数据库表中对每一行数据进行锁定,只有被锁定的行才不能被其他事务修改。行级锁可以实现更细粒度的锁控制,允许多个事务同时修改不同的行数据而不相互干扰。然而,行级锁会引入额外的开销,可能导致死锁和性能问题。
表级锁(Table-Level Locking):
表级锁是指对整个数据库表进行锁定,当一个事务获取了表级锁时,其他事务无法访问该表的任何数据。表级锁的控制粒度较大,会导致并发性能下降,因为只有一个事务可以访问整个表。
意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。
意向共享锁(IS)表示事务意图在表中的单个行(一个数据项)上设置共享锁。
意向排他锁(IX)表明事务意图在表中的单个行(一个数据项)上设置独占锁。
例子:
事务A修改user表的记录r,会给记录r上一把行级的排他锁(X),同时会给user表上一把意向排他锁(IX),
这时事务B要给user表上一个表级的排他锁就会被阻塞。
意向锁通过这种方式实现了行锁和表锁共存且满足事务隔离性的要求。
意向锁的种类:
三种:
意向共享锁(IS):如果要对一个数据库对象加S锁,首先要对其上级结点加IS 锁,表示它的后裔结点拟(意向)加 S锁,子结点只能显式的设置共享锁;
意向排他锁(IX):如果要对一个数据库对象加X 锁,首先要对其上级结点加 IX锁,表示它的后裔结点拟(意向)加X 锁。子结点只能显式设置独占锁。
共享意向排它锁(Shared Intent Exclusive Lock,简称 SIX 锁) :如果对一个数据库对象加 SIX 锁,表示对它加 S 锁,再加 IX 锁,即 SIX=S+IX。例如:事务对某个表加 SIX 锁,则表示该事务要读整个表(所以要对该表加S 锁),同时会更新个别行(所以要对该表加 IX锁),要更新的个别行加X锁。
IS 共享型意向锁
IX 排他型意向锁
S 共享锁
SIX 共享排他意向锁
X 排他锁
多粒度和意向锁的配合使用
例子:
T21读操作,T22写操作,T23读操作,T24读数据库操作
T21读操作,T22写操作 可以并发 是因为数据库DB结点,区域A1,文件Fa结点 中 IS,IX兼容 一个结点 可以共存这两种锁
T22写操作,T23读操作 不可以并发 是因为在文件Fa结点中 IX,S 不兼容 一个结点 不可以共存这两种锁
T22写操作,T24读操作 不可以并发 是因为在数据库DB结点中 IX,S 不兼容 一个结点 不可以共存这两种锁