1. 编程式事务
通过手动编写代码来实现事务。在编程式事务中有以下几个重要的接口:
- TransactionDefinition:定义了Spring兼容的事务属性(比如事务隔离级别、事务传播、事务超时、是否只读状态)
- TransactionStatus:代表了事务的具体运行状态(获取事务运行状态的信息,也可以通过该接口间接提交回滚事务等操作)
PlatformTransactionManager:事务管理器接口(定义了一组行为,具体实现交由不同的持久化框架来完成—-类比JDBC)
2. 声明式事务
声明式事务因为封装了大量的东西(一般我们使用简单,里头都非常复杂),所以声明式事务实现要难得多。在声明式事务中,除了TransactionStatus和PlatformTransactionManager接口,还有几个重要的接口:
TransactionProxyFactoryBean:生成代理对象
- TransactionInterceptor:实现对象的拦截
- TransactionAttrubute:事务配置的数据
- TransactionAspectSupport:创建事务
2.3. 声明式事务失效的场景
- @Transactional注解应用在非public修饰的方法上
- @Transactional的propagation属性设置错误
- @Transactional的属性rollbackFor设置错误
- 同一个类方法中被没有@Transactional修饰的方法调用,导致@Transactional失效
- 异常被catch捕获,导致@Transactional回滚失效
-
3. 传播行为
注意:不能同类中调用,否则传播行为基本失效
REQUIRED
- 如果当前有事务就在当前事务运行,否则创建一个新的事务,并在创建的当前事务运行
- REQUIRES_NEW
- 必须开启新的事务,并在创建的当前事务运行,如果之前有事务,那么应该将之挂起
- NESTED
- 如果当前有事务,就在当前事务的嵌套事务中运行,否则创建一个新的事务,并在创建的当前事务运行
- 嵌套的事务依托于外部事务,外部出异常,嵌套的也会回滚;内部出异常会影响外部的事务
- SUPPORTS
- 如果有事务就在事务中运行,否则也可以不在事务中运行
- NOT_SUPPORTED
- 当前方法不应该运行在事务中,如果有事务应该将它挂起
- NEVER
- 当前方法不应该运行在事务中,如果有事务,会抛出异常
- MANDATORY
- 当前方法必须运行在事务中,否则直接抛出异常
- NESTED和REQUIRED、REQUIRES_NEW的区别
@Transactional
public String getEntity() {
txService.testUpdate(); //传播行为是REQUIRED_NEW
txService.testDelete(); //传播行为是NESTED
System.out.println(1/0); //第一行不回滚,第二行回滚:因为与外层事务是一个嵌套事务
}
@Transactional
public String getEntity() {
txService.testUpdate(); //传播行为是REQUIRED_NEW
txService.testDelete(); //传播行为是REQUIRED
System.out.println(1/0); //第一行不会滚,第二行回滚:因为与外层事务是同一个事务
}