事务(transaction)是构成单一逻辑工作单元的操作集合。是访问并可能更新各种数据项的一个程序执行单元。
事务操作在数据库中要么全部正确反映出来,要么完全不反映。
隔离执行事务时,保持数据库一致性。
事务并发执行时,每个事物感觉不到其他事务在并发执行。
一个事务成功完成后,它对数据库的改变必须是永久的。
稳定存储器: 信息永远不会丢失 非易失存储器: 系统奔溃后还存在(磁盘) 易失存储器: 系统奔溃后丢失(内存)
冲突调度: 当两个事务I,J在相同的数据操作,二者至少一个含write指令,那么I和J是冲突的,二者交换属于冲突调度。 等价冲突: 调度S进过一系列非冲突指令交换成S’,称S和S’是等价冲突的。 冲突可串行化: 如果调度S和一个串行调度是冲突等价的,那么S是冲突可串行化的。 优先图: 如果T1,T2的读写、写读、写写事务都是T1在前,T2在后;那么T1–>T2。如果优先图有环,那就不是冲突可串行化的,反之则是。
可恢复调度: 如果T1读取了T2所写的数据,那么T2应该先于T1提交,否则不满足可恢复调度。 无级联调度: 单个事务故障导致一系列事务回滚称为级联回滚,调度避免无级回滚称为无级联调度。
允许事务读到未提交的数据,会发生脏读(读取到没有提交的数据)
只允许读已提交的数据,会发生不可重复读(事务两次读取一个数据,中间有一个事务更新了数据导致两次读取不一样)
只允许读取已提交的数据,并且两次读取同一数据期间不允许其他事务更新该数据;会发生幻读(事务两次读取一个数据集,一个事务做了新增操作,结果第二次读取多了几条数据)
保证串行化调度
锁: 共享锁:读事务 排它锁:写事务 时间戳: 按照事务时间戳来串行访问数据项。 多版本和快照隔离(si): 事务通过快照操作数据,提交后才会将更新写入数据库。
分类:共享锁、排它锁,可以通过升级降级转换 两阶段封锁协议:增长阶段只能获得锁,缩减阶段只能释放锁 严格两阶段封锁协议:事务持有的所有排它锁必须在事务提交后释放 强两阶段封锁协议:事务提交前不能释放任何锁 实现方式:锁表(排队)和图协议(必须获得父锁才能获得子锁) 死锁处理: 预防: 1、一次全部封锁,给数据加次序; 2、抢占与事务回滚:wait-die机制,T1申请的数据项被T2持有,T1时间戳较小(老),则T1等待,否则T1回滚,即先来的可以等后来的释放锁,后来的发现没锁拿就死亡;wound-wait机制,先来者发现锁被后来者持有,就抢过来并且杀死后来者事务,后来者发现锁被先来者持有就等待。 3、超时:等待时间超过一段时间后回滚,但是应用有限 检测: 通过等待图有无环来判断,T1–>T2代表T1等待T2释放锁 恢复: 1.选择牺牲者:回滚最小代价事务,通过时长,数据项,涉及其他事务等等因素判断 2.回滚:彻底回滚或者部分回滚 3.饿死:设置回滚次数上限,防止某一事务一直回滚被饿死 多粒度: 方便给数据集加锁,不用一个一个去加,对一个数据显式加锁,其他依赖的数据会被隐式加锁。加锁需要遵循多粒度封锁协议,根据树状图依次加锁(IS S IX X SIX)
时间戳小代表事务靠前,大的代表事务靠后。 时间戳排序协议: 1.假设事务T1发出read(Q),如果TS(T1)<W-timestamp(Q),那么T1回滚,如果TS(T1)>=W-timestamp(Q),则执行更新R-timestamp为最大值。 2.假设事务T1发出write(Q),如果T1(T1)<R-timestamp(Q)或者T1(T1)<W-timestamp(Q),T1都会回滚,否则T1执行并且更新更新W-timestamp为最大值。 Thomas写规则: 1.当T1发出write(Q),如果TS(T1)<R-timestamp(Q),T1回滚和之前一样 2.如果TS(T1)<W-timestamp(Q),则忽略T1(区别所在) 3.其他的情况执行T1并把W-timestamp(Q)设置为TS(T1)
三个阶段: 读阶段(start):数据项值被读入并保存在T1的局部变量中。 有效性检查阶段(validation):判断是否可以执行write操作 写阶段(finish):临时的局部变量值被复制到数据库中 有效性测试: 事务被要求满足TS(T1)<TS(T2)情况T1必须满足下列条件之一:1.finish(T1)<start(T2)。2.T1所写的数据项集与T2数据项集不相交,且T1的写阶段开T2开始有效性检查开始之前完成(start(T2)<finish(T1)<validation(T2))
事务write(Q)操作可以创建一个Q的新版本,当发出其他事务发出read(Q)操作时,可以选择一个版本读取以保证串行性。 时间戳排序 每个数据项包含三个数据字段:content、W-timestamp、R-timestamp Qk写时间戳小于等于TS(T1)的最大写时间戳:1.如果事务T1发出read(Q),则返回Qk的内容。2.如果事务T1发出write(Q),且若TS(T1)<R-timestamp(Qk),则事务回滚;若TS(T1)=W-timestamp(Qk),则覆盖Qk的内容;若TS(T1)>R-timestamp(Q),则创建新版本。简而言之,先于回滚同时覆盖后于新建。 两阶段封锁 数据项每个按本有一个时间戳(ts-counter)。只读事务遵循时间戳排序协议,返回小于该事务最大时间戳版本内容。更新事务先获取排它锁,再创建一个新版本,新版本时间戳为∞,等更新完成后,时间戳变为ts-counter+1