一:什么是事务?
一组业务:要么都成功,要么都失败
二:事务ACID原则
三:明确
spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现
四:事务的隔离级别 (Spring 定义了一个枚举类:Isolation)
Spring中枚举类Isolation源码
public enum Isolation {
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
private final int value;
Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
事务隔离级别解析
-
TransactionDefinition.ISOLATION_DEFAULT(default) :
使用后端数据库默认的隔离级别
MySQL 默认采用的 REPEATABLE_READ (repeatable_read) 隔离级别
Oracle 默认采用的 READ_COMMITTED (read_committed) 隔离级别. -
TransactionDefinition.ISOLATION_READ_UNCOMMITTED (uncommitted):
最低的隔离级别,使用这个隔离级别很少
因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 -
TransactionDefinition.ISOLATION_READ_COMMITTED (read_committed) :
只能读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生(Oracle默认级别) -
TransactionDefinition.ISOLATION_REPEATABLE_READ (repeatable_read) :
对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生(MySQL默认级别)。 -
TransactionDefinition.ISOLATION_SERIALIZABLE (serializable) :
最高的隔离级别,完全服从 ACID 的隔离级别。
所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。
该级别可以防止脏读、不可重复读以及幻读。
但是这将严重影响程序的性能。通常情况下也不会用到该级别。
五:事务的传播行为
REQUIRED(required):
如果当前没有事务,就新建一个事务
如果已经存在一个事务中,加入到这个事务中。一般的选择(默认值,使用的最多的事务传播行为)
SUPPORTS(supports):
支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务,事务将不会发生回滚)
MANDATORY(mandatory):
使用当前的事务,如果当前没有事务,就抛出异常 (使用的很少)
REQUERS_NEW(requers_new):
新建事务,如果当前在事务中,把当前事务挂起。
不管外部方法是否开启事务,Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
NOT_SUPPORTED(not_supported):
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起(没有事务,事务将不会发生回滚)
NEVER(never):
以非事务方式运行,如果当前存在事务,抛出异常(没有事务,事务将不会发生回滚)
NESTED(nested):
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。
如果当前没有事务,则执行 REQUIRED(required) 的操作
六:使用事务时要导入的约束
此处需要导入 aop 和 tx 两个名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
七:配置声明式事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
八:配置事务通知: 配置事务的通知引用事务管理器
<!--结合AOP实现事务的织入-->
<!-- 配置事务通知: 配置事务的通知引用事务管理器-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务 配置事务的传播特性: propagation 默认值REQUIRED
指定方法名称:是业务核心方法
read-only:是否是只读事务。默认 false,不只读。
isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。
propagation:指定事务的传播行为。
timeout:指定超时时间。默认值为:-1。永不超时。
rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。
没有默认值,任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回
滚。没有默认值,任何异常都回滚。
-->
<tx:attributes>
<!-- <tx:method name="addUser" propagation="REQUIRED"/>-->
<!-- <tx:method name="deleteUser*" propagation="REQUIRED"/>-->
<!-- <tx:method name="update*"/>-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
九:配置事务切入:配置AOP
<aop:config>
<!-- 配置切入点表达式 -->
<aop:pointcut id="txPointCut" expression="execution(* com.csnz.dao.*.*(..))"/>
<!-- 在 aop:config 标签内部:建立事务的通知和切入点表达式的关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
十:@Transactional(rollbackFor = Exception.class)注解
Exception 分为运行时异常 RuntimeException 和非运行时异常。
即使出现异常情况,它也可以保证数据的一致性。
当 @Transactional 注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性。
我们也可以在方法级别使用该标注来覆盖类级别的定义。
如果类或者方法加了这个注解,那这个类中的方法抛出异常,就会回滚,数据库中的数据也会回滚。
在 @Transactional 注解中如果不配置rollbackFor属性
那么事务只会在遇到RuntimeException的时候才会回滚
加上 rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。