您的位置:首页 > 其它

事务四大特征:原子性,一致性,隔离性和持久性(ACID)

2018-01-09 00:00 615 查看
摘要: Transaction 也就是所谓的事务了,通俗理解就是一件事情。从小,父母就教育我们,做事情要有始有终,不能半途而废。 事务也是这样,不能做一半就不做了,要么做完,要么就不做。也就是说,事务必须是一个不可分割的整体。

一、基本概念

事务的原子性(Atomicity)
事务的原子性指的是,事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据改操作要全部执行,要么全部不执行。这种特性称为原子性。 事务的原子性要求,如果把一个事务看作是一个程序,它要么完整的被执行,要么完全执行。就是说事务的操纵序列或者完全应用到数据库或者完全不影响数据库。这种特性称为原子性 假如用户在一个事务内完成了对数据库的更新,这时所有的更新对外部世界必须是可见的,或者完全没有更新。前者称事务已提交,后者称事务撤销。DBMS必须确保由成功提交的事物完成的所有操作在数据库内有完全的反映,而失败的事务对数据库完全没有影响

-------------------------------------------------------------------------------------------------------------

事务的一致性(Consistency)
指在一个事务执行之前和执行之后数据库都必须处于一致性状态。这种特性称为事务的一致性。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。(打个比方,如果从 A 账户转账到 B 账户,不可能因为 A 账户扣了钱,而 B 账户没有加钱吧)
一致性处理数据库中对所有语义约束的保护。假如数据库的状态满足所有的完整性约束,就说该数据库是一致的。例如,当数据库处于一致性状态S1时,对数据库执行一
个事务,在事务执行期间假定数据库的状态是不一致的,当事务执行结束时,数据库处在一致性状态S2

-------------------------------------------------------------------------------------------------------------

隔离性(Isolation)
隔离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被企图进行修改的事务看到 分离性是DBMS针对并发事务间的冲突提供的安全保证。DBMS可以通过加锁在并发执行的事务间提供不同级别的分离。假如并发交叉执行的事务没有任何控制。操纵相同的共享对象的多个并发事务的执行可能引起异常情况(打个比方,当我们编写了一条 update 语句,提交到数据库的一刹那间,有可能别人也提交了一条 delete 语句到数据库中。也许我们都是对同一条记录进行操作,可以想象,如果不稍加控制,就会出大麻烦来。我们必须保证数据库操作之间是“隔离”的(线程之间有时也要做到隔离),彼此之间没有任何干扰。这就是:隔离性(Isolation)。)
DBMS可以在并发执行的事务间提供不同级别的分离。分离的级别和并发事务的吞吐量之间存在反比关系。较多事务的可分离性可能会带来较高的冲突和较多的事务流产。流产的事务要消耗资源,这些资源必须要重新被访问。因此,确保高分离级别的DBMS需要更多的开销

要想真正的做到操作之间完全没有任何干扰是很难的,于是乎要制定一个规范。

1.READ_UNCOMMITTED

2.READ_COMMITTED

3.REPEATABLE_READ

4.SERIALIZABLE

千万不要去翻译,那只是一个代号而已。从上往下,级别越来越高,并发性越来越差,安全性越来越高,反之则反。

-------------------------------------------------------------------------------------------------------------

持久性(Durability)
持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。(打个比方,当我们执行一条 insert 语句后,数据库必须要保证有一条数据永久地存放在磁盘中,这个也算事务的一条特性, 它就是:持久性)即一旦一个事务提交,DBMS保证它对数据库数据的改变应该是永久性的,耐得住任何系统故障
。持久性通过数据库备份和恢复来保证 持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。即对已提交事务的更新恢复。一旦一个事务被提交,DBMS必须保证提供适当的冗余,使其耐的住系统故障。所以,持久性主要在于DBMS的恢复性能

-------------------------------------------------------------------------------------------------------------

二、三类数据读问题和两类数据更新问题

1.Dirty Read(脏读)



余额应该为 1100 元才对!请看 T6 时间点,事务 A 此时查询余额为 900 元,这个数据就是脏数据,它是事务 A 造成的,明显事务没有进行隔离,渗过来了,乱套了。

2.Unrepeatable Read(不可重复读)



事务 A 其实除了查询了两次以外,其他什么事情都没有做,结果钱就从 1000 变成 0 了,这就是重复读了。可想而知,这是别人干的,不是我干的。其实这样也是合理的,毕竟事务 B 提交了事务,数据库将结果进行了持久化,所以事务 A 再次读取自然就发生了变化。

这种现象基本上是可以理解的,但在有些变态的场景下却是不允许的。毕竟这种现象也是事务之间没有隔离所造成的,但我们对于这种问题,似乎可以忽略。

3.Phantom Read(幻读)



银行工作人员,每次统计总存款,都看到不一样的结果。不过这也确实也挺正常的,总存款增多了,肯定是这个时候有人在存钱。但是如果银行系统真的这样设计,那算是玩完了。这同样也是事务没有隔离所造成的,但对于大多数应用系统而言,这似乎也是正常的,可以理解,也是允许的。银行里那些恶心的那些系统,要求非常严密,统计的时候,甚至会将所有的其他操作给隔离开,这种隔离级别就算非常高了(估计要到 SERIALIZABLE 级别了)。

第一类丢失更新,A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来:



但是,在当前的四种任意隔离级别中,都不会发生该情况,不然绝对乱套,我都没提交事务只是撤销,就把别人的给覆盖了,这也太恐怖了。

第二类丢失更新,B事务覆盖A事务已经提交的数据,造成A事务所做操作丢失



归纳一下,以上提到了事务并发所引起的跟读取数据有关的问题,各用一句话来描述一下:

1.脏读:事务 A 读取了事务 B 未提交的数据,并在这个基础上又做了其他操作。

2.不可重复读:事务 A 读取了事务 B 已提交的更改数据。

3.幻读:事务 A 读取了事务 B 已提交的新增数据。

第一条是坚决抵制的,后两条在大多数情况下可不作考虑。

这就是为什么必须要有事务隔离级别这个东西了,它就像一面墙一样,隔离不同的事务。看下面这个表格,您就清楚了不同的事务隔离级别能处理怎样的事务并发问题:



根据您的实际需求,再参考这张表,最后确定事务隔离级别,应该不再是一件难事了。

三、JDBC事务

现在来看看MySQL数据库为我们提供的四种隔离级别:

  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

  ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

  ③ Read committed (读已提交):可避免脏读的发生。

  ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。

  在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

例1:查看当前事务的隔离级别:



例2:将事务的隔离级别设置为Read uncommitted级别:



或:



记住:设置数据库的隔离级别一定要是在开启事务之前!

如果是使用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connection对象的setAutoCommit(false)方法之前。调用Connection对象的setTransactionIsolation(level)即可设置当前链接的隔离级别,至于参数level,可以使用Connection对象的字段:



在JDBC中设置隔离级别的部分代码:



后记:隔离级别的设置只对当前链接有效。对于使用MySQL命令窗口而言,一个窗口就相当于一个链接,当前窗口设置的隔离级别只对当前窗口中的事务有效;对于JDBC操作数据库来说,一个Connection对象相当于一个链接,而对于Connection对象设置的隔离级别只对该Connection对象有效,与其他链接Connection对象无关。

四、Spring事务管理

除了 JDBC 给我们提供的事务隔离级别这种解决方案以外,还有哪些解决方案可以完善事务管理功能呢?

不妨看看 spring 的解决方案吧,其实它是对 JDBC 的一个补充或扩展。它提供了一个非常重要的功能,就是:事务传播行为(TransactionPropagation Behavior)。

Spring 提供了 7 种事务传播行为。

1.PROPAGATION_REQUIRED

2.RROPAGATION_REQUIRES_NEW

3.PROPAGATION_NESTED

4.PROPAGATION_SUPPORTS

5.PROPAGATION_NOT_SUPPORTED

6.PROPAGATION_NEVER

7.PROPAGATION_MANDATORY

首先要明确的是,事务是从哪里来?传播到哪里去?答案是,从方法 A 传播到方法 B。Spring 解决的只是方法之间的事务传播,那情况就多了,比如:

方法 A 有事务,方法 B 也有事务。

方法 A 有事务,方法 B 没有事务。

方法 A 没有事务,方法 B 有事务。

方法 A 没有事务,方法 B 也没有事务。

这样就是 4 种了,还有 3 种特殊情况。还是用我的 Style 给大家做一个分析吧:

@Transactional
void A(){
}
@Transactional
void B(){
A();
}

假设事务从方法 A 传播到方法 B,您需要面对方法 B,问自己一个问题:

方法 A 有事务吗?

如果没有,就开启一个事务;如果有,就加入当前事务(方法A加入到方法B)。这就是PROPAGATION_REQUIRED,它也是 Spring 提供的默认事务传播行为,适合绝大多数情况。

如果没有,就开启一个事务;如果有,就将当前事务挂起。这就是 RROPAGATION_REQUIRES_NEW,意思就是创建了一个新事务,它和原来的事务没有任何关系了。

如果没有,就开启一个事务;如果有,就在当前事务中嵌套其他事务。这就是 PROPAGATION_NESTED,也就是传说中的“嵌套事务”了,所嵌套的子事务与主事务之间是有关联的(当主事务提交或回滚,子事务也会提交或回滚)。

如果没有,就以非事务方式执行;如果有,就使用当前事务。这就是 PROPAGATION_SUPPORTS,这种方式非常随意,没有就没有,有就有,有点无所谓的态度,反正我是支持你的。

如果没有,就以非事务方式执行;如果有,就将当前事务挂起。这就是 PROPAGATION_NOT_SUPPORTED,这种方式非常强硬,没有就没有,有我也不支持你,把你挂起来,不鸟你。

如果没有,就以非事务方式执行;如果有,就抛出异常。这就是 PROPAGATION_NEVER,这种方式更猛,没有就没有,有了反而报错,确实够牛的,它说:我从不支持事务!

如果没有,就抛出异常;如果有,就使用当前事务。这就是 PROPAGATION_MANDATORY,这种方式可以说是牛逼中的牛逼了,没有事务直接就报错,确实够狠的,它说:我必须要有事务!

Spring 给我们带来了事务传播行为,这确实是一个非常强大而又实用的功能。除此以外,也提供了一些小的附加功能,比如:

1.事务超时(Transaction Timeout):为了解决事务时间太长,消耗太多的资源,所以故意给事务设置一个最大时常,如果超过了,就回滚事务。

2.只事务(Readonly Transaction):为了忽略那些不需要事务的方法,比如读取数据,这样可以有效地提高一些性能。

最后,推荐大家使用 Spring 的注解式事务配置,而放弃 XML 式事务配置。因为注解实在是太优雅了,当然这一切都取决于您自身的情况了。

在 Spring 配置文件中使用:

<tx:annotation-driven/>

在需要事务的方法上使用:

@Transactional
public void xxx() {
...
}

可在 @Transactional 注解中设置:事务隔离级别、事务传播行为、事务超时时间、是否只读事务。

具体使用请参考我的另一篇博客
https://my.oschina.net/idea813/blog/1582244
五、思维导向图



参考资料
https://www.cnblogs.com/lc-ant/p/3981834.html http://blog.csdn.net/u014079773/article/details/52808193
http://blog.csdn.net/lovesomnus/article/details/44459675
https://www.cnblogs.com/fjdingsd/p/5273008.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  事务
相关文章推荐