数据库管理(事务、ACID、并发、封锁、可串行化、隔离)(转)
1、数据库事务
1.1 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。
1.2 事务的4个特性(ACID):
(1)原子性(atomic)(atomicity)事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。原子性消除了系统处理操作子集的可能性。
(2)一致性(consistent)(consistency)事务在完成时,必须使所有的数据都保持一致状态。事务结束时,所有的内部数据结构(如B树索引或双向链表)都必须是正确的。
(3)隔离性(insulation)(isolation)由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状
态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,
并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。当事务可序列化时将获得最高的隔离级别。在此级别上,从一组可并行执行的事务获得的
结果与通过连续运行每个事务所获得的结果相同。由于高度隔离会限制可并行执行的事务数,所以一些应用程序降低隔离级别以换取更大的吞吐量。防止数据丢失。
(4)持久性(Duration)(durability)事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
1.3 事务有3种模型:
(1)隐式事务是指每一条数据操作语句都自动地成为一个事务;每个事务都没有显式的开始和结束标记。
(2)显式事务是指有显式的开始结束标记的事务;或者开始是隐式的,事务的结束有明确的标记。(begin transaction 事务开始--commit 事务正常结束--rollback事务出错回滚)
(3)自动事务是系统自动默认的,开始和结束不用标记。
2、并发控制
2.1 常见并发并发一致性问题包括:丢失的修改(lost update)、读脏数据(dirty read)、不可重复读(unrepeatable read)、幻影读(phantom read,又叫幻读,幻象读,非一致性读,或者幽灵数据,往往与不可重复读归为一类)。
2.2 为了解决并发不一致问题,SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
(1)ReadUncommitted(读取未提交内容)在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读。
(2)ReadCommitted(读取提交内容)这是大多数数据库系统的默认隔离级别(比如SQLSever,Oracle,但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读,因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
(3)RepeatableRead(可重读)这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致幻读。
(4)Serializable(可串行化)这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
脏读 Dirty Read | 不可重复读 Non-Repeatable Read | 错误读取/幻读/虚读 Phantom Read | |
读未提交 Read Uncommitted | √ | √ | √ |
读已提交 Read Committed | × | √ | √ |
可重复读 Repeatable Read | × | × | √ |
可串行化 Serializable | × | × | × |
2.3 为了体现隔离级别,数据库使用了封锁技术(locking)
(1)S锁,Share Locks,共享锁,读锁,被加锁的对象可以被持锁事务读取,但是不能被修改,其他事务也可以在上面再加s锁。
(2)X锁,Exclusive Locks,排他锁,写锁,被加锁的对象只能被持有锁的事务读取和修改,其他事务无法在该对象上加其他锁,也不能读取和修改该对象。
2.4 引入封锁技术又带来了“死锁”问题
解决死锁的两类方法:
(1)预防法:一次封锁法(每个事务必须将所用到的数据全部加锁,否则不能执行)和顺序封锁法(对用到的数据按照预先设定的顺序加锁)。
(2)诊断解除法:超时法(一事务超过规定时间则判定发生死锁)和等待图法(事务等待图是一个有向图G=(T,U),T为结点的集合,每个结点表示正在运行的事务;U为边的集合,每条边表示事务等待的情况。若事务T1等待事务T2,则T1,T2之间有一条有向边,从 T1 指向 T2。如果发现图中存在回路,则表示系统中出现了死锁)。
2.5 封锁协议(Locking Protocol)
2.5.1 保证数据一致性的封锁协议的三级封锁协议
对并发操作的不正确调度可能会带来的三种数据不一致性:丢失修改、不可重复读和读“脏”数据。三级封锁协议分别在不同程度上解决了这一问题。
(1)1级封锁协议:事务T修改数据R之前必须先对其X加锁,直到事务结束才释放。事务结束包括正常结束和非正常结束。1级封锁协议可防止丢失修改,并保证事务T是可恢复的。在1级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不读“脏”数据。
(2)2级封锁协议:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。2级封锁协议除防止丢失修改,还可进一步防止读“脏”数据。在2级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证保重复读。
(3)3级封锁协议:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结果才释放。3级封锁协议除防止丢失修改和不读“脏”数据外,还进一步防止了不可重复读。
2.5.2 保证并行调度可串行性的封锁协议的两段锁协议
可串行性是并行调度正确性的唯一准则,两段锁(简称2PL)协议是为保证并行调度可串行性而提供的封锁协议。
两段锁协议规定:
在对任何数据进行读、写操作之前,事务道首先要获得对该数据的封锁,而且在释放一个封锁之生,事务不再获得任何其他封锁。
所谓“两段”锁的含义是,事务分为两个阶段,第一阶段是获得封锁,也称为扩展阶段,第二阶段是释放封锁,也称为收缩阶段。
2.6 可串行化
调度是一个或多个事务的重要操作按时间排序的一个序列。
如果一个调度的动作首先是一个事务的所有动作,然后是另一个事务的所有动作,以此类推,而没有动作的混合,那么我们说这一调度是串行的。
事务的正确性原则告诉我们,每个串行调度都将保持数据库状态的一致性。 通常,不管数据库初态怎样,一个调度对数据库状态的影响都和某个串行调度相同,我们就说这个调度是可串行化的。[如果一并行调度的结果等价于某一串行调度的结果,那么这个并行调度成为可串行化的]