在Controller中添加事务管理
文章参考了此博客: https://blog.csdn.net/qq_40594137/article/details/82772545
写这篇文章之前先说明一下:
1. Controller中添加事务管理,是可行的,但是强烈不推荐,因为不符合实际开发场景,还会导致一系列问题
2. 事务请在Service处理,所有的业务逻辑请写在 Service, Service中异常请抛出,慎用 try...catch捕获异常
写这边文章的背景:
公司有个老的项目,springMVC + spring + mybatis,事务是在Service层处理的,但是之前的开发人员把很多业务逻辑写在了 Controller,出现了操作失败仍然将数据写入数据库的bug.....,于是开始研究在 Controller中添加事务管理
Controller中添加事务管理步骤:
1. spring.xml中事务配置不变
2. 在spring-mvc.xml中定义事务配置:
A: 命名空间中 加入约束 不加项目启动会报异常:
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
B: 定义事务注解解析 <tx:annotation-driven transaction-manager="transactionManager" />
3. 在需要控制事务的Controller 类或者方法上使用 @Transactional(rollbackFor = {Exception.class}) ,当出现异常回滚
需要注意的是: Controller层只支持 @Transactional 注解式事务!
关于为什么要在spring-mvc.xml中添加 <tx:annotation-driven transaction-manager="transactionManager" /> 的说明:
错误的方式----通过修改spring.xml中的配置来实现在controller中控制事务会发现事务无效,如下:
<aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* net.*.controller.*.*(..))"/></aop:config>
原因如下: spring容器和spring-mvc是父子容器。在服务器启动时,会先加载web.xml配置文件 ==> 再加载spring配置文件 ==> 再回到web.xml【加载监听器;加载过滤器;加载前端控制器】==>再加载springMVC配置文件,在Spring配置文件中,我们扫描注册的是service实现类,就算扫描注册了controller 也会在后面加载SpringMVC配置文件[扫描注册controller]覆盖掉,所以想要在controller中实现事务管理,仅在spring配置文件配置<tx:annotation-driven>或<aop:config>是没有效果的,必须将事务配置定义在Spring MVC的应用上下文(spring-mvc.xml)中。在spring-framework-reference.pdf文档中说明了: <tx:annoation-driven/>只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解
关于 @Transactional 注解的一些说明:
有篇博客写的很好,我就直接链接了 https://www.jianshu.com/p/befc2d73e487
关于@Transaction 事务不起作用的总结:
@Transaction不起作用的情况:1.静态(static )方法
2.(private)私有化方法
3.当本类的使用@Transactional的方法被本类的其它没有开启事务的方法调用时,不会开启事务。
使用@Transactional的方法被其它类调用时,按照正常的事务传播行为规则开启事务
4.未开启注解解析: 配置文件必须加<tx:annotation-driven />,否则不解析@Transactional
5.异常被try{}catch(){}捕捉到了,有异常就不会回滚。
6. 数据库引擎要支持事务: 如果是mysql,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的
项目中问题的最终处理:
由于 Controller 层中异常不能直接抛到用户,对异常进行了try{}catch(){},导致事务回滚失效,无法通过在 Controller 层添加事务管理来实现事务功能,
所以只能有用以下方式来处理:
1. 将业务逻辑代码移到 service 来处理 : 推荐方法
2. 如果业务逻辑复杂,在维护的时候无法保证逻辑正确的情况下,只有手动编写事务代码来实现回滚了,具体代码如下:(不推荐)
//在每个controller中注入transactionManager @Resource private PlatformTransactionManager transactionManager; @PostMapping(value = "setCode") @ResponseBody public void setCode(Invoice invoice, InvoiceAddress invoiceAddress,String token,String orderIDs, Integer pid,HttpServletResponse response){ DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition(); defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition); try { invoiceService.insert(token,pid,invoice); int iID= invoice.getId(); String substring = orderIDs.substring(0, orderIDs.length()-1); String[] split = substring.split(","); for (String string2 : split) { bOrderService.updateIStatus("1",string2); } invoiceOrderService.insert(iID,substring); if(Integer.parseInt(invoice.getiType())==1){ invoiceAddressService.insert(iID,invoiceAddress); } System.out.println("======制造一个运行时异常aa======"); System.out.println("运行时异常:"+100/0); //没有异常便手动提交事务 transactionManager.commit(status); printJson(response,result(200,"ok")); }catch (Exception e){ //有异常便回滚事务 transactionManager.rollback(status); e.printStackTrace(); printJson(response,result(500,"false")); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示