@Transactional注解式事务
@EnableTransactionManagement
正常情况下,需要我们的ApplicationConfiguration类加上@EnableTransactionManagement注解才能开启事务管理
Spring Data JPA 在 spring.factories 里面默认加载 TransactionAutoConfiguration类,默认采用AdviceMode.PROXY,所以默认情况的事务管理机制是代理方式
通过添加@Transactional注解式配置方法
@Transactional 源码
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
// 在多个DataSource时指定Transaction
@AliasFor("value")
String transactionManager() default "";
String[] label() default {};
// 设置事务的传播行为
Propagation propagation() default Propagation.REQUIRED;
// 用于设置底层数据库的事务隔离级别,事务隔离级别多用于处理并发情况,一般使用默认的即可
Isolation isolation() default Isolation.DEFAULT;
// 设置事务超时的秒数,默认永不超时
int timeout() default -1;
String timeoutString() default "";
// 当前事务是否为只读事务
boolean readOnly() default false;
// 设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚
Class<? extends Throwable>[] rollbackFor() default {};
// 用于设置需要进行混gun的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行回滚
// @Transactional(rollbackForClassName = "RuntimeException")
String[] rollbackForClassName() default {};
// 不需要进行回滚的异常类数组,在方法中抛出数组中异常时不进行事务回滚
Class<? extends Throwable>[] noRollbackFor() default {};
// 设置不需要进行回滚的异常类名称数组,在方法中抛出数组中的类异常时不进行回滚
String[] noRollbackForClassName() default {};
}
propagation: 传播行为
事务传播行为是指: 如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为
public enum Propagation {
// 如果当前事务存在,则加入该事务;如果没有事务则创建一个新的事务
REQUIRED(0),
// 如果当前存在事务,则加入该事务; 如果没有事务,则以非事务的方式运行
SUPPORTS(1),
// 如果当前存在事务,则加入该事务; 如果没有事务则抛出异常
MANDATORY(2),
// 创建一个新事务,如果当前存在事务,则把事务挂起
REQUIRES_NEW(3),
// 以非事务方式运行,如果当前存在事务,则把当前事务挂起
NOT_SUPPORTED(4),
// 以非事务方式运行,如果当前存在事务,则抛出异常
NEVER(5),
// 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行,如果没有事务,则该值等价于REQUIRED
NESTED(6);
private final int value;
private Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
事务隔离级别:
隔离级别是指若干个并发的事物之间的隔离程度,主要相关场景包括: 脏读取、重复读、幻读
public enum Isolation {
// 默认值,表示使用底层数据库的默认隔离级别
DEFAULT(-1),
// 一个事务可以读取另一个事务修改但还没有提交的数据,该级别不能防止脏读和不可重复读,因此很少使用该隔离级别
READ_UNCOMMITTED(1),
// 该隔离级别表示一个事务只能读取另一个事务已经提交的数据,该级别可以防止脏读,这也是大读书情况下的推荐值
READ_COMMITTED(2),
// 该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同
// 即使在多次查询之间又新增的数据满足该查询,这些新增的记录也会被忽略,该级别可以防止脏读和不可重复读
REPEATABLE_READ(4),
// 所有的事务一次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读、幻读
// 但是浙江严重影响程序的性能,通常情况下也不会用到该级别
SERIALIZABLE(8);
private final int value;
private Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}@Transactional 注解可以设置在方法或者类上,一般都设置在方法上
需要注意的几点:
- @Transactional 只能被应用到public方法上,兑取其他非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能
- 用Spring事务管理器,由Spring来负责数据库的打开、提交、回滚,默认遇到RuntimeException会回滚,而遇到Exception不会回滚,这个可以在rollBackFor 上设置
- @Transactional注解可以被应用于接口定义和接口方法、类定义和类public方法上,但是@Transactional仅仅是一种元数据,能够被识别
- Spring团队建议是在具体的类或方法实现上使用@Transactional注解,而不要使用在高层级的类或方法上,注解是不能被继承的,如果正在使用基于类的代理时,那么事务的设置不能被基于类的代理所识别
- 事务有两种配置方法,一种是显式的注解事务,在注解式事务下,不加service方法上是没有任何事务的,还有一种是隐式事务,AspectJ的思路配置方法
声明式事务
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
public static final String transactionExecution = "execution (* com.banywl.study.studyspringdatajpa.dao.*.*(**))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(){
// 设置拦截哪些类
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(transactionExecution);
// 配置 advisor
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
// 指定不同的方法使用不同的策略
Properties properties = new Properties();
properties.setProperty("get*","PROPAGATION_REQUIRED,-Exception");
properties.setProperty("add*","PROPAGATION_REQUIRED,-Exception");
properties.setProperty("save*","PROPAGATION_REQUIRED,-Exception");
properties.setProperty("update*","PROPAGATION_REQUIRED,-Exception");
properties.setProperty("delete*","PROPAGATION_REQUIRED,-Exception");
// 创建并设置事务拦截器
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager,properties);
advisor.setAdvice(txAdvice);
return advisor;
}
}
















