数据库事务的四大特性

事务(transaction)是由一系列操作序列构成的程序执行单元,这些操作要么都做,要么都不做,是一个不可分割的工作单位。

数据库事务的四个基本性质(ACID)

1. 原子性(Atomicity)

事务的原子性是指事务中包含的所有操作要么全做,要么全不做(all or none)。

2. 一致性(Consistency)

在事务开始以前,数据库处于一致性的状态,事务结束后,数据库也必须处于一致性状态。

拿银行转账来说,一致性要求事务的执行不应改变A、B 两个账户的金额总和。如果没有这种一致性要求,转账过程中就会发生钱无中生有,或者不翼而飞的现象。事务应该把数据库从一个一致性状态转换到另外一个一致性状态。

一致性,维基百科:

Consistency in database systems refers to the requirement that any given database transaction must change affected data only in allowed ways. Any data written to the database must be valid according to all defined rules, including constraintscascadestriggers, and any combination thereof. This does not guarantee correctness of the transaction in all ways the application programmer might have wanted (that is the responsibility of application-level code) but merely that any programming errors cannot result in the violation of any defined database constraints.

数据库的一致性泛指数据库事务必须只能以指定/可允许的方式修改数据。任何写进数据库的数据必须是合乎所有定义的规则,包括约束,级联?(cascades),触发器和其中各种规则的组合。

这些并不能保证应用希望的事务的正确性,仅仅是任何程序错误不能导致违反数据库。(转成中文好拗口...

3. 隔离性(Isolation)

事务隔离性要求系统必须保证事务不受其他并发执行的事务的影响,也即要达到这样一种效果:对于任何一对事务T1 和 T2,在事务 T1 看来,T2 要么在 T1 开始之前已经结束,要么在 T1 完成之后才开始执行。这样,每个事务都感觉不到系统中有其他事务在并发地执行。

4. 持久性(Durability)

一个事务一旦成功完成,它对数据库的改变必须是永久的,即便是在系统遇到故障的情况下也不会丢失。数据的重要性决定了事务持久性的重要性。

事务的隔离性理解

事务处理之父Jim Gray对事务隔离性的定义:

Isolation: Concurrently executing transactions see the stored information as if they were running serially (one after another).

事务的隔离级别从低到高有:
Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
通常,在工程实践中,为了性能的考虑会对隔离性进行折中。
 
其中只有serialization实现隔离性所有要求,在真正实现事务的隔离性。
但考虑到实践,为了性能,数据库厂商做出了这方面的妥协,让使用者可以选择隔离的级别。
不同的隔离级别可以解决不同阶段的问题,是层层递进,逐渐增强的关系。
 
隔离性为了解决的问题主要有三个(将事务的隔离级别和问题联系在一起理解):

        1、 脏读(Drity Read):事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。

   Read Committed可以解决脏读问题,但仍存在以下两种问题。

         2、不可重复读(Non-repeatable read) : 在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这导致锁竞争加剧,影响性能。(另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。待了解。。)

   Repeated Read可以解决不可重复读问题和脏读问题,但仍无法解决下面的问题。

         3、幻读(Phantom Read) : 在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读仅指由于并发事务增加记录导致的问题,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

    Serialization解决了以上所有问题,但是性能效率较低。
   通常来说,事务隔离级别越低,所需持有锁的时间也就越短,并发性能也就越好。

 
 
  扩展阅读:
  

MySQL数据库的InnoDB存储引擎是支持事务的引擎,其默认事务隔离级别为REPEATABLE READ(简称RR)。ANSI SQL标准下RR事务隔离级别是Degree 2.9999的隔离性,但是与ANSI SQL标准不同的是,InnoDB存储引擎在RR的事务隔离级别下就解决了幻读问题,从而实现Degree 3的隔离性要求,从而达到了真正隔离性的要求。对比其他数据库,要达到真正的事务隔离性要求,必须将事务隔离级别设置为SERIALIZABLE。换句话说,MySQL InnoDB的默认事务隔离级别可以理解为其他数据库的SERIABLIZABLE级别。

然而,从严格意义上来说,InnoDB的RR事务隔离级别的实现与传统的SERIALIAZABLE事务隔离级别还是有些不一样,这导致在某些特定场景下会给用户有错愕抑或不能接受的感觉,比如唯一索引列在一个事务中允许重复值存在。不过这并不会破坏事务的一致性,只要理解InnoDB存储引擎的锁与MVCC的实现,其实有些怪异的现象都好理解。

SNAPSHOT事务隔离级别

经典的SERIALIAZABLE事务隔离级别采用严格的两阶段锁(strict two-phrase lock,简称:STPL)实现,这也是Jim Gray在书中提及的方法。但是由于读写都需要上锁,这样导致在大部分情况下事务的性能都不如类似RC(READ COMMITTED)这样的事务隔离级别。

为了解决性能问题,最近越来越多的数据库开始支持SNAPSHOT事务隔离级别(简称SI),如Oracle、PostgreSQL、Microsoft SQL Server数据库等。SI事务隔离级别貌似解决了Dirty Read、Unrepeatable Read和Phantom Read问题。可惜的是,其依然不符合真正隔离性的要求,其存在write skew的异常问题。2008年的SIGMOD大会上,有人提出了Serializable Snapshot Isolation(SSI),从而解决了之前SI事务隔离级别存在的问题。PostgreSQL9.1版本在此论文基础上实现了SSI事务隔离级别并做了相应的优化。此外,在2012年的VLDB大会上PostgreSQL发布了相应的论文,有兴趣的读者可以继续研究。

基于快照的事务隔离级别(不论SI还是SSI)性能较之经典的SERIALIZABLE事务隔离级别提升非常多,但其存在两个问题不容忽视。一是其会导致“错误”的回滚,因为其策略就是保证正确,虽然有时可能会误杀一些没有问题的事务。二是对于大事务的支持需要额外的内存保证,如果修改的数据量特别大,那么这可能会导致内存溢出的问题发生。但不论怎么说,SSI可能都是未来的一个默认事务隔离级别发展的方向。期待MySQL数据库也能尽快支持。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值