Spring事务控制
1.什么是事务?
事务是逻辑上的一组操作,组成这组操作的基本逻辑单元,要么都成功,要么都失败.
2.事务的特性?(ACID)
- 原子性:事务是一个原子操作,由一系列动作组成,要么都成功,要么都失败
- 一致性:事务执行操作前后,无论成功还是失败,数据都应该保持一致
- 隔离性:可能有多个事务同时处理同一个数据,他们之间不会相互影响.每个事务都应和其他的事务隔离开
- 持久性:事务一旦完成,结果会长久保存
3.事务定义信息
- 隔离级别
- 传播行为
- 超时信息
- 是否只读
4.安全问题
- 脏读:一个A事务读取了另一个B事务尚未提交的信息,如果改动在稍后被回滚了,那么这个A事务获取的数据无效
- 不可重复读:同一个事务中,对于同一数据,执行完全的select语句,可能看到不同的结果
- 幻读:当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行;
5.Spring进行事务操作方式
编 程 式 事 务
在 项 目 中 很 少 使 用 , 这 种 方 式 需 要 注 入 一 个 事 务 管 理 对 象 TransactionTemplate ,然后在我们代码中需要提交事务或回滚事务时自己写代码实现.
声明式事务管理
-
基于xml配置文件方式
-
配置事务管理器,并注入数据源
<!-- 配置 spring 事务管理类, 并注入数据源 --> <bean id="transactionManager" <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
-
Xml配置
<tx:advice id="txadvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut expression="execution(* com.lwb.service.*(..))" id="allMethod"/> <aop:advisor advice-ref="txadvice" pointcut-ref="allMethod"/> </aop:config>
-
思想就是AOP
-
基于注解方式
-
配置事务管理器,并注入数据源
<!-- 配置 spring 事务管理类, 并注入数据源 --> <bean id="transactionManager" <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
-
注解配置
<!-- 开启注解事务管理 --> <tx:annotation-driven transaction-manager="transactionManager"/>
-
实体类
@Service @Transactional //默认为@Transactional(propagation=Propagation.REQUIRED) public class UserService { @Autowired UserDao userDao; @Autowired LogService logService; }
-
6.Spring事务传播行为
什么叫事务传播行为?
即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。 事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事 务方法调用时,这个事务方法应该如何进行。事务传播行为是 Spring 框架独有 的事务增强特性,他不属于的事务实际提供方数据库行为
例如:A 方法调用 B 事务方法时,B 是继续在调 用者 A 的事务中运行呢,还是为自己开启一个新事务运行,这就是由 B 的事务传播行为决定的。
事务传播行为类型 | 说明 | |
---|---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,,加入到这个事务中。 | 如果A不是事务方法,就新建一个事务,反之,加入到A这个事务中 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 | 如果A不是事务方法,B也就没有事务,反之,加入到A这个事务中 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 | 如果A不是事务方法,抛出异常,反之,加入到A这个事务中 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 | B是一个新的独立的事务.A事务异常不会影响B事务 |
PROPAGATION_NOT_SUPPOR TED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 | B以非事务的方式进行,执行完后执行被挂起的A |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 | 如果A不是事务方法,B以就非事务的方式进行,反之,抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。 | 如果A不是事务方法,就新建一个事务,反之,就会在在嵌套事务内执行 |
-
嵌套事务
嵌套事务是一个外部事务的一个子事务,是一个外部事务的一个组成部分,当嵌套事务发生异常,而回滚,则会回复到嵌套事务的执行前的状态,相当于嵌套事务未执行。如果外部事务回滚,则嵌套事务也会回滚!!!外部事务提交的时候,它才会被提交。
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 潜套事务也会被 commit, 这个规则同样适用于 roll back.
-
事务的传播行为失效的场景
- 不能在同一个类中的方法互相调用
- 出现异常被catch捕获了
- 修饰非public方法
- 传播行为配置错误