【Java】@Transactional注解
参考文章:Spring——事务注解@Transactional,by 七海健人
@Transactional 来源于 Spring,用来管理事务。该注解属于 Spring 的声明式事务,还有一种是编程式事务,编程式对代码具有侵入性,不推荐使用。
注解的使用
可以用在接口、类、方法:
- 接口:不推荐,Spring AOP 使用 CGLib 时,注解会失效
- 类:生效于类中所有 public 方法
- 方法:类和方法同时配置,方法注解会覆盖类注解
注解属性
public @interface Transactional {
/**
* 当在配置文件中有多个 TransactionManager , 可以用该属性指定选择哪个事务管理器。
*/
@AliasFor("transactionManager")
String value() default "";
/**
* 同上。
*/
@AliasFor("value")
String transactionManager() default "";
/**
* 事务的传播行为,默认值为 REQUIRED。
*/
Propagation propagation() default Propagation.REQUIRED;
/**
* 事务的隔离规则,默认值采用 DEFAULT。
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* 事务超时时间。
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* 是否只读事务
*/
boolean readOnly() default false;
/**
* 用于指定能够触发事务回滚的异常类型。
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* 同上,指定类名。
*/
String[] rollbackForClassName() default {};
/**
* 用于指定不会触发事务回滚的异常类型
*/
Class<? extends Throwable>[] noRollbackFor() default {};
/**
* 同上,指定类名
*/
String[] noRollbackForClassName() default {};
}
失效的场景
- 注解在非 public 方法上
- 注解在 final 方法上
- 同一个类中,某方法调用事务方法
- 解决办法一:事务方法新写一个 Service,然后类中注入使用
- 解决方法二:当前类中,注入自己,参考Spring——循环依赖&三级缓存
- 解决办法三:使用
AopContext.currentProxy()获取当前类的代理对象
@Servcie
public class ServiceA {
public void save(User user) {
queryData1();
queryData2();
((ServiceA)AopContext.currentProxy()).doSave(user);
}
@Transactional(rollbackFor=Exception.class)
public void doSave(User user) {
addData1();
updateData2();
}
}
- 事务方法所在类,没有被 Spring 管理,例如没有加
@Service注解 - 数据库存储引擎不支持事务:mysql 的 myisam 不支持事务
- 两个方法不在同一线程中,即是两个不同的事务
Spring 中的传播方式和隔离级别
七种传播方式👇
// 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值
1. Propagation.REQUIRED
// 创建一个新的事务,如果当前存在事务,则把当前事务挂起
2. Propagation.REQUIRES_NEW
// 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
3. Propagation.SUPPORTS
// 以非事务方式运行,如果当前存在事务,则把当前事务挂起
4. Propagation.NOT_SUPPORTED
// 以非事务方式运行,如果当前存在事务,则抛出异常
5. Propagation.NEVER
// 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
6. Propagation.MANDATORY
/*
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
*/
7. Propagation.NESTED
五种隔离级别👇
// 使用后端数据库默认的隔离级别 对于MYSQL来说就是可重复读
1. Isolation.DEFAULT
// 是最低的隔离级别,允许读取尚未提交的数据变更(会出现脏读,不可重复读),基本不使用
2. Isolation.READ_UNCOMMITTED
// 允许读取并发事务已经提交的数据(会出现不可重复读和幻读)
3. Isolation.READ_COMMITTED
// 事物开启后,对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改(会出现幻读)
4. Isolation.REPEATABLE_READ
// 最高的隔离级别,完全服从ACID的隔离级别,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的
5. Isolation.SERIALIZABLE

浙公网安备 33010602011771号