Spring 事务处理
@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; } }

浙公网安备 33010602011771号