数据库原理与安全笔记: 事务
该部分为本科期间数据库原理与安全笔记备份。
Transaction Concept
transaction:a unit of program execution that accesses and possibly updates various data items.
访问并可能更新各种数据项的一个程序执行单元
特征:用户定义的,人为规定;要么全做,要么全不做;DMBS操作数据库的基本单位
一个数据库操作序列,一个不可分割的工作单位,恢复和并发控制的基本单位
事务和程序比较:
- 在关系数据库中,一个事务可以是一条或多条SQL语句,也可以包含一个或多个程序。
- 一个程序通常包含多个事务
- 事务一般有应用程序员提出,保证事务的原子性,一次性完成有DBMS提供保证
条件:
- A transaction must see a consistent database.
- During transaction execution the database may be inconsistent.
- When the transaction is committed, the database must be consistent
事务可以保证数据库的一致性,是DBMS操作一组数据库操作保证一致性的手段
ACID Properties
- Atomicity:原子性
- Either all operations of the transaction are properly reflected in the database or none are.
- Consistency:一致性
- Execution of a transaction in isolation preserves the consistency of the database
- Isolation:隔离
- each transaction must be unaware of other concurrently executing transactions.
- Intermediate transaction results must be hidden from other concurrently executed transactions
- Durability:持久性
- After a transaction completes successfully, the changes it has made to the database persist, even if there are system failures
Transaction State
- Active:initial state
- the transaction stays in this state while it is executing
- Partially committed
- after the final statement has been executed
- Failed
- after the discovery that normal execution can no longer proceed.
- Aborted
- after the transaction has been rolled back and the database restored to its state prior to the start of the transaction
- Two options after it has been aborted
- restart the transaction – only if no internal logical error
- kill the transaction
- Committed
- after successful completion
事务故障:某个事务在运行过程中由于种种原因未运行至正常终止点就夭折了
Concurrency control
Multiple transactions are allowed to run concurrently in the system. Advantages are:
- increased processor and disk utilization,leading to better transaction throughput
- reduced average response time for transactions
多事务同时执行方式
串行执行
每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行
缺点:不能充分利用系统资源,发挥数据库共享资源的特点
交叉并发方式
Interleaved Concurrency
在单处理机系统中,事务的并行执行是这些并行事务的并行操作轮流交叉运行
优点:能够减少处理机的空闲时间,提高系统的效率
缺点:单处理机系统中的并行事务并没有真正地并行运行
同时并发方式
simultaneous concurrency
可能带来不一致性
并发存在的问题:
- 丢失修改:事务1与事务2从数据库中读入同一数据并修改,事务2的提交结果破坏了事务1提交的结果,导致事务1的修改被丢失。
- 不可重复读:事务1读取数据后,事务2执行更新操作,使事务1无法再现前一次读取结果。
“脏”数据:事务1修改某一数据并写回,事务2读取同一数据后事务1由于某种原因被撤消,这时事务1已修改过的数据恢复原值事务2读到的数据就与数据库中的数据不一致,其不正确的数据为“脏”数据。
Concurrent Executions
Concurrency control schemes
mechanisms to achieve isolation, i.e., to control the interaction among the concurrent transactions in order to prevent them from destroying the consistency of the database
problems:occur when concurrent transactions access the same items
Schedules
sequences that indicate the chronological(按年代顺序排列的 ) order in which instructions of concurrent transactions are executed
条件:
- a schedule for a set of transactions must consist of all instructions of those transactions
- must preserve the order in which the instructions appear in each individual transaction
N个事务的一个调度S是N个事务的所有操作的一个序列,表示这些操作的执行顺序,并且满足对于N个事务中的每个事务T,如果操作i在T中先于操作j执行,则在S中操作i也必须先于操作j执行。
多个事务的调度保持每个事务的操作在该事务中的顺序不变。但是,不同事务的操作可以交叉执行。
不同的并行事务调度会产生不同的结果
Serial Schedule(串行调度)
不同的串行调度产生的结果可能不一致,但是数据库都是一致性状态,就是正确的。
串行化的调度一定能使数据库达到一致性的状态,但是串行调度会牺牲性能。
事务调度与可串行性
一个事务的所有操作都执行完后才执行另一个事务的所有操作。称这样的调度为串行调度,表示了事务的串行运行。
其他类型的调度为并行调度。
调度的可串行性:
- 每个事务独立运行时不会引起任何问题,串行调度一定产生正确的运行结果。但串行调度限制了系统并发性的发挥。
- 并行调度可能导致不正确的事务运行结果!
- 希望并行调度能够和串行调度具有相同的效果,这需要确定具有串行调度效果的系统方法,即可串行性理论。
Serializability
可串行化
Basic Assumption:Each transaction preserves database consistency
Thus serial execution of a set of transactions preserves database consistency
A (possibly concurrent) schedule is serializable if it is equivalent to a serial schedule.
几个事务的并行执行是正确的,当且仅当其结果与按某一次序串行地执行它们时的结果相同。这种并行调度策略称为可串行化(Serializable)的调度。
Conflict Seriazability
冲突串行化
如果一组语句的执行顺序不影响结果,则不冲突,反之,冲突。
Instructions \(l_i\) and \(l_j\) of transactions \(T_i\) and \(T_j\) respectively, conflict if and only if there exists some item Q accessed by both \(l_i\) and \(l_j\), and at least one of these instructions writes Q.
example
- \(l_i\) = read(Q), \(l_j\) = read(Q). \(l_i\) and \(l_j\) don’t conflict.
- \(l_i\) = read(Q), \(l_j\) = write(Q). They conflict.
- \(l_i\) = write(Q), \(l_j\) = read(Q). They conflict.
- \(l_i\) = write(Q), \(l_j\) = write(Q). They conflict.
If \(l_i\) and \(l_j\) are consecutive in a schedule and they do not conflict, their results would remain the same even if they had been interchanged in the schedule.
如果两条语句的顺序影响数据库中Q的值,就是冲突的
Conflict Serializable Schedule
If a schedule S can be transformed into a serial schedule by a series of swaps of non-conflicting instructions, we say that S is conflict serializable
如果一个调度S可以通过调换不同事务中不冲突语句的执行顺序,转换成一个串行化调度。
Implementation of Isolation
- Schedules must be serializable.
- A policy in which only one transaction can execute at a time generates serial schedules, but provides a poor degree of concurrency.
- Concurrency-control schemes tradeoff between the amount of concurrency they allow and the amount of overhead that they incur.
并发控制应该能够保证事务是并发的,同时保证事务的调度是冲突可串行化的。
Testing for Serializability:schedule is not serializable if there is a circle.
Lock-Based Protocols
A lock is a mechanism to control concurrent access to a data item
封锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁
加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。
封锁是实现并发控制的一个非常重要的技术
Data items can be locked in two modes:
- exclusive (X) mode:Data item can be both read as well as written. X-lock is requested using lock-X instruction.
- shared (S) mode: Data item can only be read. S-lock is requested using lock-S instruction.
Lock requests are made to concurrency-control manager. Transaction can proceed only after request is granted.
Should only allow conflict-serializable schedules.
锁的范围可以是数据库,关系,元组,元组的属性。
每个事务在存取一个数据项之前必须获得这个数据项上的锁。
一个事务需要获得的锁的类型依赖于它将在数据项上执行什么样的操作。
给定一个各种类型锁的集合,如下定义这个锁集合上的相容关系:
令A和B表示任意类型的锁。设事务Ti在数据项Q上要求一个A型锁,事务\(T_j\) (\(T_i≠T_j\))已经在Q上有一个B型锁。如果事务\(T_i\)能够获得Q上的A型锁,则说A型锁和B型锁是相容的。
Lock-Compatibility Matrix: 锁相容矩阵,锁之间的相容关系可以使用一个矩阵来表示。矩阵的元素COMP(A, B)=true
当且仅当A型锁与B型锁是相容的。
基于锁的并发控制协议
事务通过执行LOCK-S(Q)
操作申请数据项Q上的共享锁。
事务通过执行LOCK-X(Q)
操作申请数据项Q上的互斥锁。
UNLOCK(Q)
操作用来释放数据项Q上的锁。
要求:
- 如果事务T要存取数据项Q,T必须申请在Q上加锁。如果数据项Q已经被其他的事务加以非共享锁,则事务T必须等待,直到所有其他事务的非共享锁全部被释放。
- 事务T可以释放它在任何数据项上所加的任何类型的锁。
注意谨慎地使用锁:
- 一个事务只要存取一个数据项,它就必须持有该数据项上的一个锁。
- 如果一个事务完成了对一个数据项的最后一次存取之后就立即放弃它的锁,则不能确保调度的可串行性。
- 如果为了获得最大的并发性而尽早地释数据项的锁,则可能导致不一致的数据库状态。
- 如果我们在申请其他锁之前不尽量地释放已拥有的锁,则可能导致死锁
死锁:一个事务对x加锁,一个事务对y加锁。A事务执行完成,还需要对y加锁才可以。同样,B事务执行完成,还需要对x进行加锁才可以。所以构成了死锁。
当死锁发生时,系统必须放弃至少一个处于死锁状态的事务,释放这个事务所加锁的数据项,使其他事务可以继续运行。
锁协议:系统中的每个事务在加锁或释放锁时,都必须遵循一组规则,它规定了事务对每个数据项加锁和释放锁的时机。
The Two-Phase Locking Protocol
封锁方法:两段锁(Two-Phase Locking,简称2PL)协议
内容
- 在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁
- 在释放一个封锁之后,事务不再获得任何其他封锁。
注意:对一个事务而言,而不是多个事务。
两个阶段
- 第一阶段是获得封锁,也称为扩展阶段(Growing Phase)
- transaction may obtain locks
- transaction may not release locks
- 第二阶段是释放封锁,也称为收缩阶段(Shrinking Phase)
- transaction may release locks
- transaction may not obtain locks
一次封锁法要求统一对所有资源加锁。
一次封锁法要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行,因此一次封锁法遵守两段锁协议,但是两段锁协议并不要求事务必须一次将所有要使用的数据全部加锁,因此遵守两段锁协议的事务可能发生死锁。
推论:
- If a schedule is executed by 2PL it must be conflict serializable。
- transactions can be serialized in the order of their lock points
- If a schedule is conflict serializable it may or may not be executed by 2PL
对于任何一个事务而言,在调度中该事务获得其最后一个锁(由DBMS的并发控制管理器负责授予)的时刻称为事务的封锁点。调度中多个事务可以根据它们的封锁点进行排序。实际上,这样的一个顺序就是事务的一个可串行化次序。
既然所有的加锁动作都在解锁之前,想要使用的资源必须要先占有他,自然不会发生冲突。所以说事务遵守两段锁协议是可串行化调度的充分条件,而不是必要条件。可串行化的调度中,不一定所有事务都必须符合两段锁协议。
Lock Conversions
改善的两段锁协议:
- 当事务\(T_i\)提交一个READ(Q)操作时,系统先执行LOCK-S(Q)操作,然后再执行READ(Q)操作。
- 当事务\(T_i\)提交一个WRITE(Q)操作时,系统检查\(T_i\)是否已持有Q上的一个共享锁。如果是这样,系统先执行UPGRADE(Q)操作,然后再执行WRITE(Q)操作;否则,系统先执行LOCK-X(Q)操作,然后再执行WRITE(Q)操作。
改善的两个阶段
- First Phase:
- can acquire a lock-S on item
- can acquire a lock-X on item
- can convert a lock-S to a lock-X (upgrade)
- Second Phase:
- can release a lock-S
- can release a lock-X
- can convert a lock-X to a lock-S (downgrade)
FAQ 为什么锁提升只能发生在事务的增长阶段,而锁降级只能发生在事务的缩减阶段?
因为锁提升就相当于给事务加某些特征的锁,例如将共享锁提升为排他锁,因此提升只能发生在事务的增长阶段;而锁降级就相当于给事务解部分锁,所以锁降级只能发生在事务的缩减阶段。
Strict 2PL
Here a transaction must hold all its exclusive locks till it commits/aborts.
Cascading roll-back: the situation where the failure of a transaction \(T_i\) may lead to failures of other transactions (because they read items written by Ti before its commitment)
Rigorous two-phase locking
here all locks are held till commit/abort.
In this protocol transactions can be serialized in the order in which they commit.
Lock protocol in commercial DBMS
strict two-phase locking
+ Lock Conversions
Rigorous two-phase locking
+ Lock Conversions
Pitfalls of Lock-Based Protocols
活锁:系统可以使某个事务一直处于等待的状态,得不到封锁的机会。
Starvation:also possible if concurrency control manager is badly designed.
饥饿:等待时间大于执行时间
解除活锁
采用先来先服务的策略
- 当多个事务请求封锁同一数据对象时按请求封锁的先后次序对这些事务排队
- 该数据对象上的锁一旦释放,首先批准申请队列中第一个事务获得锁
Deadlock Handling
Deadlock prevention:Deadlock prevention protocols ensure that the system will never enter into a deadlock state.
Deadlock Detection,Deadlock Recovery:Some transaction will have to rolled back (made a victim) to break deadlock.
产生死锁的原因:两个或多个事务都已封锁了一些数据对象,然后又都请求对已为其他事务封锁的数据对象加锁,从而出现死等待。
预防死锁
预防死锁:破坏产生死锁的条件
一次封锁法
要求每个事务必须一次将所有要使用的数据全部加锁,否则就不能继续执行
Require that each transaction locks all its data items before it begins execution (predeclaration).
一次封锁法存在的问题:
- 降低并发度:扩大封锁范围。将以后要用到的全部数据加锁,势必扩大了封锁的范围,从而降低了系统的并发度
- 难于事先精确确定封锁对象:数据库中数据是不断变化的,原来不要求封锁的数据,在执行过程中可能会变成封锁对象,所以很难事先精确地确定每个事务所要封锁的数据对象
结论:
- 在操作系统中广为采用的预防死锁的策略并不很适合数据库的特点
- DBMS在解决死锁的问题上更普遍采用的是诊断并解除死锁的方法
因为操作系统的操作不是随机的,而数据库的操作都是随机的。
其他策略
- wait-die scheme — non-preemptive
- older transaction may wait for younger one to release data item. Younger transactions never wait for older ones; they are rolled back instead.
- a transaction may die several times before acquiring needed data item
- wound-wait scheme — preemptive
- older transaction wounds (forces rollback of) younger transaction instead of waiting for it. Younger transactions may wait for older ones.
- Timeout-Based Schemes
- a transaction waits for a lock only for a specified amount of time. After a pre-defined waiting period, the transaction is rolled back.
- Simple to implement; but starvation is possible. Also difficult to determine good value of the timeout interval.
Deadlock Detection
- wait-for graph(等待图):G = (V,E)
- V is a set of vertices (all the transactions in the system)
- E is a set of edges; each element is an ordered pair \(T_i→T_j\)
- \(T_i→T_j\):\(T_i\) is waiting for \(T_j\) to release a data item
- deadlock state: if and only if the wait-for graph has a cycle
Deadlock Recovery
并发控制子系统周期性地(比如每隔数秒)生成事务等待图,检测事务。如果发现图中存在回路,则表示系统中出现了死锁。
When deadlock is detected :
- Some transaction rolled back (made a victim) to break deadlock.(select victim that will incur minimum cost)
- Rollback -- determine how far to roll back transaction
- Total rollback: Abort and restart
- More effective to roll back transaction
- Starvation happens if same transaction is always chosen as victim.
- Include the number of rollbacks in the cost factor to avoid starvation
Locking with Multiple Granularity(粒度)
When a transaction locks a node in the tree explicitly, it implicitly locks all the node's descendents in the same mode.
Granularity of locking:
- fine granularity (lower in tree): high concurrency(并发), high locking overhead
- coarse granularity (higher in tree): low locking overhead, low concurrency
选择封锁粒度的原则
- 多粒度封锁(Multiple Granularity Locking): 在一个系统中同时支持多种封锁粒度供不同的事务选择;
- 选择封锁粒度
- 需要处理多个关系的大量元组的用户事务: 以数据库为封锁单位
- 需要处理大量元组的用户事务:以关系为封锁单元
- 只处理少量元组的用户事务:以元组为封锁单位
多粒度封锁协议
允许多粒度树中的每个结点被独立地加锁:
- 对一个结点加锁意味着这个结点的所有后裔结点也被加以同样类型的锁
- 一个数据对象可能以两种方式封锁:显式封锁和隐式封锁
显式封锁和隐式封锁:效果一样
显式封锁: 直接加到数据对象上的封锁
隐式封锁: 该数据对象没有独立加锁,是由于其上级结点加锁而使该数据对象加上了锁
系统检查封锁冲突时:要检查显式封锁,还要检查隐式封锁。
Intention Lock Modes
意向锁:提高对某个数据对象加锁时系统的检查效率
意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。
three additional lock modes with multiple granularity:
- intention-shared (IS):indicates explicit shared locks at a lower level of the tree.意向共享锁
- intention-exclusive (IX): indicates explicit exclusive locks at a lower level, e.g., insert a new sailor – the SAILOR file must be locked in IX mode意向排它锁
- shared and intention-exclusive (SIX):共享意向排它锁
- 以该节点为根的节点显式加S锁
- 树的更低层次显式加X锁
- SIX=S+IX
在关系数据库中,节点可以是数据库、关系表或元组。为了锁住一个下级粒度对象,事务必须用一种较弱的加 锁方式首先锁住它的上级祖先对象。其目的是把对细小粒度加锁的影响用一种适当的意向锁传播到大粒度。这样,在对一个元组上设置读锁之前,事务必须先对该关 系表设置一个意向读IS锁。类似的,事务在一个元组上设置写锁之前,必须先对该关系表设置一个意向写IX锁。
IS锁:如果对一个数据对象加IS锁,表示它的后裔结点拟(意向)加S锁。
IX锁:如果对一个数据对象加IX锁,表示它的后裔结点拟(意向)加X锁。
SIX锁:如果对一个数据对象加SIX锁,表示对它加S锁,再加IX锁,即SIX = S + IX。
兼容性: