2.4 事务与并发控制

事务规范了数据库操作的语义,每个事务使得数据库从一个一致的状态原子地转移到另一个一致的状态。数据库事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability),即ACID属性,这些特性使得多个数据库事务并发执行时互不干扰,也不会获取到中间状态的错误结果。

多个事务并发执行时,如果它们的执行结果和按照某种顺序一个接着一个串行执行的效果等同,这种隔离级别称为可串行化。可串行化是比较理想的情况,商业数据库为了性能考虑,往往会定义多种隔离级别。事务的并发控制一般通过锁机制来实现,锁可以有不同的粒度,可以锁住行,也可以锁住数据块甚至锁住整个表格。由于互联网业务中读事务的比例往往远远高于写事务,为了提高读事务性能,可以采用写时复制(Copy-On-Write,COW)或者多版本并发控制(Multi-Version Concurrency Control,MVCC)技术来避免写事务阻塞读事务。

2.4.1 事务

事务是数据库操作的基本单位,它具有原子性、一致性、隔离性和持久性这四个基本属性。

(1)原子性

事务的原子性首先体现在事务对数据的修改,即要么全都执行,要么全都不执行,例如,从银行账户A转一笔款项a到账户B,结果必须是从A的账户上扣除款项a并且在B的账户上增加款项a,不能只是其中一个账户的修改。但是,事务的原子性并不总是能够保证修改一定完成了或者一定没有进行,例如,在ATM机器上进行上述转账,转账指令提交后通信中断或者数据库主机异常了,那么转账可能完成了也可能没有进行:如果通信中断发生前数据库主机完整接收到了转账指令且后续执行也正常,那么转账成功完成了;如果转账指令没有到达数据库主机或者虽然到达但后续执行异常(例如写操作日志失败或者账户余额不足),那么转账就没有进行。要确定转账是否成功,需要待通信恢复或者数据库主机恢复后查询账户交易历史或余额。事务的原子性也体现在事务对数据的读取上,例如,一个事务对同一数据项的多次读取的结果一定是相同的。

(2)一致性

事务需要保持数据库数据的正确性、完整性和一致性,有些时候这种一致性由数据库的内部规则保证,例如数据的类型必须正确,数据值必须在规定的范围内,等等;另外一些时候这种一致性由应用保证,例如一般情况下银行账务余额不能是负数,信用卡消费不能超过该卡的信用额度等。

(3)隔离性

许多时候数据库在并发执行多个事务,每个事务可能需要对多个表项进行修改和查询,与此同时,更多的查询请求可能也在执行中。数据库需要保证每一个事务在它的修改全部完成之前,对其他的事务是不可见的,换句话说,不能让其他事务看到该事务的中间状态,例如,从银行账户A转一笔款项a到账户B,不能让其他事务(例如账户查询)看到A账户已经扣除款项a但B账户却还没有增加款项a的状态。

(4)持久性

事务完成后,它对于数据库的影响是永久性的,即使系统出现各种异常也是如此。

出于性能考虑,许多数据库允许使用者选择牺牲隔离属性来换取并发度,从而获得性能的提升。SQL定义了4种隔离级别。

●Read Uncommitted(RU):读取未提交的数据,即其他事务已经修改但还未提交的数据,这是最低的隔离级别;

●Read Committed(RC):读取已提交的数据,但是,在一个事务中,对同一个项,前后两次读取的结果可能不一样,例如第一次读取时另一个事务的修改还没有提交,第二次读取时已经提交了;

●Repeatable Read(RR):可重复读取,在一个事务中,对同一个项,确保前后两次读取的结果一样;

●Serializable(S):可序列化,即数据库的事务是可串行化执行的,就像一个事务执行的时候没有别的事务同时在执行,这是最高的隔离级别。

隔离级别的降低可能导致读到脏数据或者事务执行异常,例如:

●Lost Update(LU):第一类丢失更新:两个事务同时修改一个数据项,但后一个事务中途失败回滚,则前一个事务已提交的修改都可能丢失;

●Dirty Reads(DR):一个事务读取了另外一个事务更新却没有提交的数据项;

●Non-Repeatable Reads(NRR):一个事务对同一数据项的多次读取可能得到不同的结果;

●Second Lost Updates problem(SLU):第二类丢失更新:两个并发事务同时读取和修改同一数据项,则后面的修改可能使得前面的修改失效;

●Phantom Reads(PR):事务执行过程中,由于前面的查询和后面的查询的期间有另外一个事务插入数据,后面的查询结果出现了前面查询结果中未出现的数据。

表2-3说明了隔离级别与读写异常(不一致)的关系。容易发现,所有的隔离级别都保证不会出现第一类丢失更新,另外,在最高隔离级别(Serializable)下,数据不会出现读写的不一致。

2.4 事务与并发控制 - 图1