1传统事务介绍 · SpringCloud微服务实战 · 看云

导航

对于传统的单体是应用事务原子性(Atomictiy)、一致性(Consistency)、隔离型(Isolation)、持久性(Durability),也就是我们常说的ACID,在我们应用中使用关系型数据库的时候,数据库为我们提供了ACID的特性,强一致性事务

以下我们以我们常用的关系型数据库Mysql来说明

1. 下面是传统事务的介绍

  • 原子性(Atomicity)
    原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • 一致性(Consistency)
    一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  • 隔离性(Isolation)
    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  • 持久性(Durability)
    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

2. 事务隔离级别

SQL标准定义了以下几种事务隔离级别:

  • READ_UNCOMMITTED 读未提交:最低级别,一个事务可以读取另一个未提交事务的数据。幻读、不可重复读和脏读都允许。
  • READ_COMMITTED 读已提交:一个事务要等另一个事务提交后才能读取数据。允许幻读、不可重复读,不允许脏读。
  • REPEATABLE_READ 可重复读:在开始读取数据(事务开启)时,不再允许修改操作。允许幻读,不允许不可重复读和脏读。
  • SERIALIZABLE 可串行化:最高级别,在该级别下,事务串行化顺序执行。幻读、不可重复读和脏读都不允许。

2.1 幻读、不可重复读和脏读介绍

2.1.1 脏读

脏读是指一个事务读取了未提交事务执行过程中的数据。
当一个事务的操作正在多次修改数据,而在事务还未提交的时候,另外一个并发事务来读取了数据,就会导致读取到的数据并非是最终持久化之后的数据,这个数据就是脏读的数据。
最典型的例子就是银行转账,从A账户转账100到B账户,脚本命令为

update table set money = money + 100 where username = 'B';
update table set money = money - 100 where username = 'A';

在这个事务执行过程中,另外一个事务读取结果发现B账户中的钱已经到账,提示B钱已到账,B就进行了下一步的操作。但是最终转账事务失败,导致操作回滚。实际上B并未收到钱,但是进行了下一步的操作,造成了损失,这就是脏读。

2.1.2 不可重复读

不可重复读是指对于数据库中的某个数据,一个事务执行过程中多次查询返回不同查询结果,这就是在事务执行过程中,数据被其他事务提交修改了。
不可重复读同脏读的区别在于,脏读是一个事务读取了另一未完成的事务执行过程中的数据,而不可重复读是一个事务执行过程中,另一事务提交并修改了当前事务正在读取的数据。

2.1.3 虚读(幻读)

幻读是事务非独立执行时发生的一种现象,例如事务T1批量对一个表中某一列列值为1的数据修改为2的变更,但是在这时,事务T2对这张表插入了一条列值为1的数据,并完成提交。此时,如果事务T1查看刚刚完成操作的数据,发现还有一条列值为1的数据没有进行修改,而这条数据其实是T2刚刚提交插入的,这就是幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点同脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

3. Spring五种事务隔离

  • DEFAULT 使用数据库设置的隔离级别(默认),由 DBA 默认的设置来决定隔离级别;
  • READ_UNCOMMITTED 会出现脏读、不可重复读、幻读(隔离级别最低,并发性能高);
  • READ_COMMITTED  会出现不可重复读、幻读问题(锁定正在读取的行);
  • REPEATABLE_READ 会出幻读(锁定所读取的所有行);
  • SERIALIZABLE 保证所有的情况不会发生(锁表)。

4. Spring七个事务传播行为

在TransactionDefinition接口中定义了七个事务传播行为:

  • PROPAGATION_REQUIRED  如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。这是Spring默认的传播行为。
  • PROPAGATION_SUPPORTS  如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行。但是对于事务同步的事务管理器,PROPAGATION_SUPPORTS与不使用事务有少许不同。
  • PROPAGATION_MANDATORY  如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
  • PROPAGATION_REQUIRES_NEW  总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
  • PROPAGATION_NOT_SUPPORTED  总是非事务地执行,并挂起任何存在的事务。
  • PROPAGATION_NEVER  总是非事务地执行,如果存在一个活动事务,则抛出异常。
  • PROPAGATION_NESTED  如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。