转自:

  https://blog.csdn.net/cp026la/article/details/86496788

扯淡:

  复杂的业务逻辑中一个请求可能需要多次操作数据库,要保证一个Service 方法中多个 dao 的操作同时成功(失败),事务的配置就很重要了。

大概分三种情况:

  1、分布式事务:即多模块中事务,分布式事务建议是可以避免就避免,可以使用消息中间件处理,但也不能完全解决。
  2、多线程事务:参考:https://blog.csdn.net/kongkongyanan/article/details/81703415
  3、单模块中的事务,本章的重点,也是开发中遇到的最多的,这里给出两种配置方式。

  本章分别使用注解 @Transactional (springboot默认推荐)和 AOP 全局配置的方式:

pom 依赖(延续上一章代码)增加aop的依赖:

<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

一、事务演示:

需要引入spring-boot-starter-jdbc依赖,但是我们集成了mybatis,已经包含了该依赖,不必重复引入。
1、controller层代码:在UserController中添加测试的方法

 @GetMapping
@RequestMapping(value = "add/{number}")
public ApiResult add(@PathVariable("number") Integer number){
userService.addUser(number);
return ApiResult.ok();
}

2、service层代码:在UserService中添加测试方法,设置一个可控的除以0异常

    public void addUser(int number){
User user = new User();
user.setId(22);
user.setName("xiaoming");
user.setAge(12);
mapper.insertSelective(user); int num = 10/number; User user2 = new User();
user2.setId(23);
user2.setName("xiaohong");
user2.setAge(90);
mapper.insertSelective(user2);
}  

3、测试
3.1、请求接口:http://localhost:8080/user/add/10 数据库正常插入两条数据

3.2、删除刚插入的两条数据。请求接口:http://localhost:8080/user/add/0 制造除以0 异常。
现象:数据库此时只插入第一条数据(xiaoming)。
分析:插入第二条数据(xiaohong)之前,出现除以0异常,造成程序中断。

需求: 这种在同一个逻辑中的多个dao操作要么同时成功、要么同时失败,不允许只成功一个dao操作的情况出现。

二、使用@Transactional 配置事务:

1、在service层addUser 方法上添加@Transactional注解

    @Transactional(rollbackFor = Exception.class)
public void addUser(int number){
...
}

2、测试:删除数据库中已经成功插入的数据。
2.1、请求接口:http://localhost:8080/user/add/0 制造除以0 异常。
2.2、结果:出现除以0 异常,数据库并未插入任何数据,即实现了多个dao操作同时成功,同时失败。

3、注意点:

1、spring 事务默认回滚的是运行时异常(RuntimeException)和错误(Error),非检测异常,例如SQLException 不会回滚。加上rollbackFor = Exception.class 可解决。
2、在service中使用了try catch 捕获了异常,事务不会回滚,因为try catch 异常之后就相当于没有异常,建议异常在controller中统一处理。

三、使用 AOP 全局处理事务:

需要引入 aop 的依赖。

1、新建全局事务配置类(个人放置到config包中,方便管理):

/**
* spring aop 配置全局事务
*/
@Aspect
@Configuration
public class TransactionAdviceConfig { /*
* 定义切入点
* execution()是最常用的切点函数
* execution (com.coolron.user.service.impl..*.*(..))
* 1、execution(): 表达式主体。
* 2、第一个*号:表示返回类型,*号表示所有的类型。
* 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
* 4、第二个*号:表示类名,*号表示所有的类。
* 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
*/
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.coolron.user.service.impl..*.*(..))"; @Autowired
private PlatformTransactionManager transactionManager; @Bean
public TransactionInterceptor txAdvice() { DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true); NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); // service 中方法前缀
source.addTransactionalMethod("add*", txAttr_REQUIRED);
source.addTransactionalMethod("save*", txAttr_REQUIRED);
source.addTransactionalMethod("delete*", txAttr_REQUIRED);
source.addTransactionalMethod("update*", txAttr_REQUIRED); return new TransactionInterceptor(transactionManager, source);
} @Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
} }  

2、测试:
将 Service 中addUser 方法上的 @Transactional 注解注释,删除数据。
2.1、请求接口:http://localhost:8080/user/add/10 正常操作,数据库插入两条数据。
2.2、删除刚插入的两条数据。请求接口:http://localhost:8080/user/add/0 制造除以0 异常。
结果:出现异常,数据库并未插入数据。

3、注意点:

1、正确配置切入点的位置,本章配置的是:
execution(* com.coolron.user.service.impl….(…)),也可将user换成 * 指定多个位置
2、service 层中方法名应严格按照全局事务配置类中定义的规则来命名。
3、try catch 同样也不要在service中使用。

至此,单模块中的事务配置已完成,也是平时开发中最遇到的,对于分布式事务(即多模块),尽量将涉及到事务的业务逻辑放到一个模块中处理,使用消息中间件处理也不是最佳方案。

【springboot】事务处理的更多相关文章

  1. Springboot 事务处理常见坑点

    使用事务注解@Transactional 之前,应该先了解它的相关属性,避免在实际项目中踩中各种各样的坑点. 常见坑点1:遇到非检测异常时,事务不开启,也无法回滚. 例如下面这段代码,账户余额依旧增加 ...

  2. SpringBoot学习笔记(9)----SpringBoot中使用关系型数据库以及事务处理

    在实际的运用开发中,跟数据库之间的交互是必不可少的,SpringBoot也提供了两种跟数据库交互的方式. 1. 使用JdbcTemplate 在SpringBoot中提供了JdbcTemplate模板 ...

  3. springboot实现定时任务,异步操作,统一结果返回,全局异常处理,拦截器及事务处理

    本文是作者原创,版权归作者所有.若要转载,请注明出处. 本文都是springboot的常用和实用功能,话不多说开始吧 定时任务 1.启动类开启注解 @EnableScheduling //开启基于注解 ...

  4. (十四)SpringBoot之事务处理

    一.简介 ssh ssm都有事务管理service层通过applicationContext.xml配置,所有service方法都加上事务操作: 用来保证一致性,即service方法里的多个dao操作 ...

  5. Springboot全局事务处理

    什么是全局事务 Spring Boot(Spring)事务是通过aop(aop相关术语:通知(Advice).连接点(Joinpoint).切入点(Pointcut).切面(Aspect).目标(Ta ...

  6. SpringBoot | 1.4 数据库事务处理

    前言 前面讲解了Sring的AOP,可以知道它是用来抽取公共代码,增强方法的.而在JDBC操作数据库进行数据处理时,有很多重复的公共代码:事务的提交与回滚跟AOP的约定流程很相似.因此,Spring数 ...

  7. springboot多个service互相调用的事务处理(十三)

    在一个service的方法A中,调用另一个service的方法B,方法A和方法B均存在数据库插入操作,需要添加如下配置: @Transactional(rollbackFor = Exception. ...

  8. Springboot数据访问,棒棒哒!

    Springboot对数据访问部分提供了非常强大的集成,支持mysql,oracle等传统数据库的同时,也支持Redis,MongoDB等非关系型数据库,极大的简化了DAO的代码,尤其是Spring ...

  9. SpringBoot系列——Spring-Data-JPA

    前言 jpa是ORM映射框架,更多详情,请戳:apring-data-jpa官网:http://spring.io/projects/spring-data-jpa,以及一篇优秀的博客:https:/ ...

随机推荐

  1. 解决IDEA右侧maven不显示方法

    解决IDEA右侧maven不显示方法 Ctrl+shift+A --> maven--> add maven projects -->选择对应的pom.xml

  2. C#曲线分析平台的制作(四,highcharts+ajax加载后台数据)

    在上一篇博客:C#曲线分析平台的制作(三,三层构架+echarts显示)中已经完成了后台的三层构架的简单搭建,为实现后面的拓展应用开发和review 改写提供了方便.而在曲线分析平台中,往往有要求时间 ...

  3. 类加载机制+JVM调优实战+代码优化

    类加载机制 Java源代码经过编译器编译成字节码之后,最终都需要加载到虚拟机之后才能运行.虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直 ...

  4. 大数据学习(07)——Hadoop3.3高可用环境搭建

    前面用了五篇文章来介绍Hadoop的相关模块,理论学完还得操作一把才能加深理解.这一篇我会花相当长的时间从环境搭建开始,到怎么在使用Hadoop,逐步介绍Hadoop的使用. 本篇分这么几段内容: 规 ...

  5. RTC为何这么火?

    国内疫情已经接近尾声,有疫情的原因孵化的音视频互动类 App数量出现井喷式增长,通讯场景被资本关注,市场持续走高.在线教育.娱乐社交.直播带货等领域逆势增长,也带动了开发者们对于 IM 和RTC能力的 ...

  6. http request 请求拦截器,有token值则配置上token值

    // http request 请求拦截器,有token值则配置上token值 axios.interceptors.request.use( config => { if (token) { ...

  7. GooseFS助力大数据业务数倍提升计算能力

    前言 GooseFS是由腾讯云推出的一款分布式缓存方案,主要针对包括需要缓存加速的数据湖业务场景,提供基于对象存储COS服务的近计算端数据加速层. GooseFS 基于开源大数据缓存方案 Alluxi ...

  8. 小白学习vue第五天-第二弹(全局局部、父子、注册语法糖,script/template抽离模板)

    全局组件: 就是注册的位置在实例对象的外面 并且可以多个实例对象使用 而局部: 就是在实例对象的内部注册 父组件和子组件的关系 子组件就是在另一个组件里面注册的组件 组件注册语法糖: 就不用Vue.e ...

  9. 用 区间判断(if)来猜价格的高低

    1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int price = 150; 6 int gue ...

  10. Spring Cloud Alibaba - Feign

    Feign Feign简介 使用Feign实现消费者客户端 使用Feign+Ribbon实现客户端负载均衡 底层的负载均衡策略还是使用Ribbon通过Feign进行调用 Feign的相关配置 ribb ...