Spring声明式事务
程序员文章站
2022-07-05 18:19:00
...
Spring提供了对事务的支持,它提供了两种实现方式:编程式
、声明式
。编程式一般用于细粒度的事务,声明式一般用于粗粒度的事务。通常开发中使用的是声明式事务,可以通过简单配置和注解的方式快速无侵入地实现事务。
声明式事务的实现步骤如下:
Step1:添加事务依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
Step2:Spring配置文件中配置事务管理器、开启注解
<!-- 配置事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置基于注解的声明式事务-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
Step3:@Transactionl注解可以用于方法和类(包括接口)上,建议仅在需要的方法上使用此注解
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
参数详解
1. propagation(传播行为)
当前事务方法被另一个事务方法调用时,必须指定事务应该如何传播(即被调用的方法如何工作在调用方法的事务中,如:方法可以在现有事务中运行,也可以开启一个新的事务并在自己的事务中运行)。
Spring提供了7种事务的传播行为
-
REQUIRED(默认值)
必须在一个具有事务的上下文中运行:如果当前没有(外层)事务,就新建一个事务;如果当前存在(外层)事务,则加入到当前(外层)事务中。(如果被调用方法发生异常,那么调用方法和被调用方法的事务都将回滚)这是最常用的选择。 -
SUPPORTS
支持当前(外层)事务,如果当前没有(外层)事务,就以非事务方式执行。 -
MANDATORY
强制使用当前(外层)事务,如果当前没有(外层)事务,就抛出异常。 -
REQUIRES_NEW
新建一个事务,并在该事务中运行,如果当前存在(外层)事务,则先将当前(外层)事务挂起 -
NOT_SUPPORTED
以非事务方式执行操作:如果当前存在(外层)事务,就把当前(外层)事务挂起。 -
NEVER
以非事务方式执行:如果当前存在(外层)事务,则抛出异常。 -
NESTED
以嵌套方式执行:如果当前存在(外层)事务,则以嵌套方式独立运行于自己的事务中,不影响当前(外层)事务,而当前(外层)事务如果回滚,则该事务也必须回滚;如果当前不存在(外层)事务,则执行与PROPAGATION.REQUIRED类似的操作。
2. isolation(隔离级别)
Spring声明式事务提供了对数据库事务隔离级别的支持(事务隔离级别的介绍可以看我的另一篇文章:数据库事务)
-
DEFAULT
使用数据库默认的事务隔离级别 -
READ_UNCOMMITTED
允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读 -
READ_COMMITTED
允许从已经提交的事务读取,可防止脏读,但幻读、不可重复读仍然有可能发生 -
REPEATABLE_READ
对相同字段的多次读取的结果是一致的,除非数据被当前事务自身修改。可防止脏读和不可重复读,但幻读仍有可能发生 -
SERIALIZABLE
完全服从ACID隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
3. readOnly
指定事务是否为只读,表示该事务是否只读取数据但不更新数据,只有读取操作的事务设置为只读可以帮助数据库引擎优化事务。
4. timeout
事务的开始往往都会发生数据库的表锁或者被数据库优化为行锁,如果允许时间过长,那么这些数据会一直被锁定,影响系统的并发性。为了尽量缩短事务执行时间,可以给这些事务设置超时时间,以秒为单位。
5. rollbackFor、noRollbackFor等
默认情况下,Spring声明式事务默认对所有的运行时异常进行回滚,如有特殊情况可以通过上rollbackFor、noRollbackFor等进行特殊的指定。(一般情况下不会用到)