Spring Boot(九)之声明式事务使用总结

1. Spring事务机制

目前市面上所有的数据访问存储技术都支持事务处理机制,用于提供给API开启事务、提交事务、回滚操作等。Spring支持声明式事务,即使用注解来选择需要使用事务的方法,使用@Transactional注解在方法上表明该方法需要事务支持。在该方法被调用时,Spring会开启一个新事务。

Spring Boot使用事务支持非常方便,首先在配置类或者启动类中加上开启事务的注解:

1
@EnableTransactionManagement

其次,在你需要加事务的方法上,加注解:

1
2
3
4
@Transactional
public boolean someMethod() {
// 处理
}

完成以上两步骤,你的这个someMethod方法就支持事务管理了。

2. Transactional属性分析

@Transactional注解可以配置如下一些属性:

属性 说明
propagation 事务传播行为
isolation 事务隔离级别
timeout 超时时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。
readOnly 读写属性配置,默认false,如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。
rollbackFor 回滚规则,定义异常回滚Class
rollbackForClassName 回滚规则,异常回滚名String
noRollbackFor 回滚规则,遇到不回滚Class
noRollbackForClassName 回滚规则,遇到不回滚String

2.1 事务传播行为

事务传播行为是Spring独有的事务管理属性,不属于事务实际提供方数据库的行为。这是Spring为我们提供的强大的工具箱,使用事务传播行可以为我们的开发工作提供许多便利。事务传播行为用来描述由某一个事务传播行为修饰的方法被嵌套进另一个方法的时事务如何传播。以以下代码为例:

1
2
3
4
5
6
7
8
9
public void methodA() {
methodB();
//doSomething
}
@Transactional(propagation = XXX, isolation = XXX)
public void methodB() {
//doSomething
}

代码中methodA()方法调用了methodB()方法,methodB()的事务传播行为由@Transactional(propagation = XXX, isolation = XXX)决定。这里需要注意的是methodA()并没有开启事务,某一个事务传播行为修饰的方法并不是必须要在开启事务的外围方法中调用。

org.springframework.transaction.annotation.Propagation.java中,定义了7种事务的传播行为:

  • REQUIRED,如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是Spring默认的选择。
  • SUPPORTS,如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • MANDATORY,如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  • REQUIRES_NEW,创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • NOT_SUPPORTED,以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • NEVER,以非事务方式运行,如果当前存在事务,则抛出异常。
  • NESTED,如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则执行与REQUIRED类似的操作。

2.2 事务隔离级别

隔离性是事务ACID特性里最复杂的一个。在SQL标准里定义了四种隔离级别,每一种级别都规定一个事务中的修改,哪些是事务之间可见的,哪些是不可见的。级别越低的隔离级别可以执行越高的并发,但同时实现复杂度以及开销也越大。

org.springframework.transaction.annotation.Isolation.java中定义了和MySQL保持一致的四个隔离级别:

  • DEFAULT(使用数据库默认隔离级别)。
  • READ_UNCOMMITTED(未提交读),事务可以读其他事务未提交的数据,优点是读写并行,性能高,缺点是容易产生脏读问题。
  • READ_COMMITTED(提交读),一个事务只能读取另一个事务已经提交的数据,该级别会产生不可重读以及幻读问题,这跟READ COMMITTED 级别下的MVCC机制有关系,在该隔离级别下每次 select的时候新生成一个版本号,所以每次select的时候读的不是一个副本而是不同的副本。在每次select之间有其他事务更新了我们读取的数据并提交了,那就出现了不可重复读。

image

  • REPEATABLE_READ(可重复读),MySQL默认的隔离级别,一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同,这种级别下可以避免,脏读,不可重复读等查询问题。

image

  • SERIALIZABLE(事务依次执行),不会产生数据读取不一致问题,但是性能最低;
隔离级别 脏读 不可重复读 幻读 加锁读
READ_UNCOMMITTED YES YES YES NO
READ_COMMITTED NO YES YES NO
REPEATABLE_READ NO NO YES NO
SERIALIZABLE NO NO NO YES

以上内容就是关于Spring Boot(九)之声明式事务使用总结的全部内容了,谢谢你阅读到了这里!

Author:zhaoyh