Spring提供两种事务管理方式,分为编程式和声明式。
- 编程式:通过编码的方式手动启用、提交或回滚事务,粒度更细,但更麻烦。
- 声明式:通过在方法或类或接口上添加注解进行包装,无侵入地实现事务,更方便,但粒度更大。
需要注意的是,使用的数据库需要支持事务,否则事务将不起作用。如MySql的MyIsam引擎就不支持事务。
2.实例 业务代码在下面的实例中,我要先创建申请,再创建申请处理。如果创建申请处理失败,应该回滚。这里是没加事务的。为了演示,我们先注掉第7行,模拟出错。
@Override
public boolean saveTransaction(CertApply certApply) {
certApply.setState(1); //初审中
save(certApply);
ApplyDeal applyDeal = new ApplyDeal();
applyDeal.setState(1); //初审
applyDeal.setApplyId(certApply.getId());
applyDealService.save(applyDeal);
return true;
}
运行测试
显然出现了我们要看到的问题
接下来开始使用事务进行管理
开启事务管理org.springframework spring-tx ${spring.version}
@SpringBootApplication
@EnableAspectJAutoProxy
@EnableTransactionManagement
@MapperScan("com.example.course_system.mapper")
public class CourseSystemApplication {
public static void main(String[] args) {
SpringApplication.run(CourseSystemApplication.class, args);
}
}
在方法上加上@Transaction注解
@Override
@Transactional
public boolean saveTransaction(CertApply certApply) {
certApply.setState(1); //初审中
save(certApply);
ApplyDeal applyDeal = new ApplyDeal();
applyDeal.setState(1); //初审
// applyDeal.setApplyId(certApply.getId());
applyDealService.save(applyDeal);
return true;
}
测试
没有新的记录加入。结果正确!
4.SpringBoot实现声明式事务的几种方式-
基于动态代理支持@Transaction。
就是上面的那种方法。但这种方法是有局限性的。在有些情况下会失效。
- 同一个类中,方法A实现了事务,方法B中没实现事务,B中调用A。事务失效(没有经过代理类,俗称自调用问题)
- 数据库引擎不支持事务
- 没有被 Spring 管理
- 方法不是 public 的
- 异常被吃了 (高频)异常类型错误(一定要抛出RuntimeException,或者配置识别的事务类型)
-
基于AspectJ编译期织入来支持@Transactional
- 用来解决上面的方法不是public的时候动态代理失效的问题
我们可以采用“编译期织入”或“类加载期织入”的方式,在运行代码前,将我们的目标类的方法增强,无需管用“动态代理”实现时的种种限制。本文就接下来就讲下,如何使用AspectJ来实现在编译期对@Transactional注解的方法进行织入。
5.1.导包5.2.配置org.codehaus.mojo aspectj-maven-plugin 1.11 org.springframework spring-aspects 1.8 1.8 1.8 true compile
将@EnableTransactionManagement中的mode设置为AdviceMode.ASPECTJ(默认为AdviceMode.PROXY,也就是我们的动态代理~)
然后就可以啦。这里就不测试,用兴趣的同学可以去实验下。
6.一些补充知识 6.1Transaction注解的源码@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
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 {};
}
参考:事务传播机制 https://blog.csdn.net/qq_35493807/article/details/105756761
Class extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
参考:事务传播机制 https://blog.csdn.net/qq_35493807/article/details/105756761



