数据库——事务

来源:互联网 发布:巅峰减重 知乎 编辑:程序博客网 时间:2024/05/19 02:03

1. 事务概念

构成单一逻辑工作单元的操作集合称为事务。由begin transaction 和end transaction 之间执行的全体操作组成。


2. ACID 特性

Atomicity 原子性:要么全执行,要么全不执行。

Consistency 一致性:事务执行前后,数据库都处于一致状态,一致性要求超出包含了数据完整性约束(主码约束,参照完整性,check约束等)。

Isolation 隔离性::并发的事务之间相互隔离,其运行结果与串行的计算过运行结果相同。

Durability 持久性:一旦事务提交,事务对数据库的影响是永久性的。

3. 事务状态

活动的 active:初始状态,事务执行时处于这个状态。

部分提交的 partially committed :最后一条语句执行后(还没提交,可能会出现故障)。

失败的 failed :发现正常的执行不能继续后。

中止的 aborted :事务回滚并且数据库已恢复到事务开始执行前的状态。

提交的 committed : 成功完成后。

当事务不能继续正常执行时,事务就进入中止状态,此时,系统有两种选择:

a 重启事务: 引起事务中止的是硬件错误 

b 杀死事务 : 引起事务中止的的事务的内部逻辑造成的错误。


4. 事务并行运行的好处:

a 提高吞吐量和资源利用率

b 减少事务等待时间


5. 事务异常情况及隔离性级别

参考资料 点击打开链接

1》异常情况

a 脏读(Dirty Read)

当一个事务读取另一个事务尚未提交的修改时,产生脏读。

同一事务内不是脏读。 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚,也就是说读取出的数据其实是错误的。

b 非重复读(Nonrepeatable Read) 一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。

c 幻像读(Phantom Reads) 事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。

当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。

d 丢失修改(Lost Update)

第一类:当两个事务更新相同的数据源,如果第一个事务被提交,第二个却被撤销,那么连同第一个事务做的更新也被撤销。

第二类:有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。


2》隔离级别(由高到低)

a 未提交读(Read Uncommitted)

直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别的事务可以读到这个改变。

Read Uncommitted 允许脏读。

b 已提交读(Read Committed)

直译就是"读提交",意思就是语句提交以后,即执行了 Commit 以后别的事务就能读到这个改变,只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别。

Read Commited 不允许脏读,但会出现非重复读。

c 可重复读(Repeatable Read):

直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的。

Repeatable Read 不允许脏读,不允许非重复读,但是会出现幻象读。

d 串行读(Serializable)

直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行。完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

Serializable 不允许不一致现象的出现。


6. 重要概念

a 调度

一组事务之间的执行顺序称为调度,一组事务的一个调度包含了这一组事务的全部指令。

b 可恢复调度

一个可恢复调度应满足:对于每对事务A和B,如果B 读取了之前由A 所写的数据项,则 A应该先于B 提交。这样就可以避免 B先提交后,A中止而B不能回滚的情况,保证了在这种情况下,可以回滚恢复到最初的状态,所以叫可恢复调度。

c 无极联调度

因为一个事务故障导致一系列事务回滚的现象称为级联回滚。

无级联回滚应满足: 对于每对事务A 和 B, 如果B 读取了先前A所写的数据项,则 A必须在B 这一读操作前提交。这样就可以避免这样的情况:B读取了A所写的数据项,而A中止,导致A回滚,B也回滚产生的级联回滚。

d 可串行化调度

事务调度的结果与没有并行化调度的结果是一样的调度就称为可串行化调度。

e 冲突

对于同一个数据项,只要事务中有一个是写操作,则事务之间就是冲突的。

对于不同的数据项,事务之间是不冲突的。

如果调度S 可以经过一系列非冲突指令交换转化成S‘ , 则S和S’ 是冲突等价的。不是所有的串行调度相互之间都冲突等价(理解:串行调度只强调调度的结果和没有并行化调度的结果是一样的,而冲突等价是指交换非冲突指令后,可以变成另一个调度,而且这两个调度的最终结果是一样的。例如事务A 和事务B, 如果先执行A 再执行B 和先执行 B再执行 A的结果不同,但这两个调度都是串行调度,而对于先执行A 后执行 B的调度来说,交换这个调度中间的非冲突指令,得到的结果只会和原来的调度的结果相同,而绝不会和先执行B 后执行 A 的调度的结果相同)。

根据冲突理论,可以将事务之间对数据项的访问用 优先图 来表示,如果调度S 的优先图有环,说明S是非冲突可串行的,如果优先图无环,则调度S 是冲突可串行化的 。这里,可串行是我们希望的结果,并不是说事务所有调度都是可串行的。


7. 隔离性级别的实现

a 锁

b 时间戳

c 多版本和快照隔离


8. 基于锁的协议的并发控制

1》饿死:事务A申请数据项Q的排他锁,而事务B已经得到了数据项Q的共享锁,所以事务A需要等待事务B释放锁,而等待时,事务C1,C2,C3对数据项Q申请共享锁,导致事务A一直处于等待的状态就称为饿死。

当事务A对数据项Q申请加M锁时,为了避免事务A饿死,控制管理器授权加锁的条件是:

a 不存在在数据项Q上持有与M型锁冲突的锁的其他事务。

b 不存在等待对数据项Q加锁且先于A申请加锁的事务。(先来先服务,比A事务先申请的事务先得到锁)

2》两阶段封锁协议

保证可串行性的一个协议是两阶段封锁协议,该协议要求每个事务分两个阶段提出加锁和解锁申请。

a 增长阶段 growing phase : 事务可以获得锁,但不能释放锁。事务中获得最后加锁位置称为事务的封锁点。

b 缩减阶段 shrinking phase :事务可以释放锁,但不能获得新锁,一旦事务释放了锁,它就进入了缩减阶段。

3》严格两阶段封锁协议

严格两阶段封锁协议除了要求封锁是两阶段之外,还要求事务持有的所有排他锁必须在事务提交后方可释放。严格两阶段封锁可以避免级联回滚。

4》强两阶段封锁协议

强两阶段封锁协议要求事务提交之前不得释放任何锁

严格两阶段封锁协议和强两阶段封锁协议在商用数据库系统中广泛使用。


9. 封锁的实现(数据库系统理论6th P377)

一个数据项维护一个链表,每个请求为链表中一条记录,按请求到达的顺序排序。

锁管理器处理请求:

a 当一条锁请求消息到达时,如果相应数据项的链表存在,在该链表末尾增加一个记录,否则,新建一个仅包含该请求记录的链表。

    在当前没有加锁的数据项上总是授予第一次加锁请求,但当事务向已被加锁的数据项申请加锁时,只有当该请求与当前持有的锁相容,并且所有先前的请求都已授予锁的条件下,锁管理器才为该请求授予锁,否则,该请求等待。

b 当锁管理器收到一个事务的解锁消息时,他将与该事务相对应的数据项链表中的记录删除,然后检查随后的记录,如果有,就看该请求能否被授权,如果能,锁管理器授权该请求并处理其后记录,如果还有,类似地一个接一个处理(只要相容,就可以授予锁)。

c 如果一个事务中止,锁管理器删除该事物产生的正在等待加锁的所有请求。一旦数据库系统撤销该事务,该中止事务持有的锁都将释放。

原创粉丝点击