Spring中同一个service中方法相互调用事务不生效问题解决方案
问题描述:
我们在用Spring框架开发Web项目过程中,经常需要用同一个service中的一个方法调用另一个方法,如果此时调用方没有添加事务注解@Transactional,而在被调用方添加事务注解@Transactional,当被调用方法中出现异常,这时候会发现事务并没有回滚,事务注解@Transactional没有起作用。
分析原因:
我们知道Spring中事务管理是使用AOP代理技术实现的,目标对象自身并没有事务管理功能的,而是通过代理对象动态增强功能对事务进行增强的。因此当我们在同一个service类中通过一个方法调用另一个方法时,是通过目标对象this对象调用的,目标对象自身并没有事务管理功能,因此事务不能生效。
下面我们用代码演示下:
public class UserService{...public User getUserByName(String name) {return userDao.getUserByName(name);}...
如果配置了事务, 就相当于又创建了一个代理类:
public class UserServiceProxy extends UserService{private UserService userService;...public User getUserByName(String name){User user = null;try{// 在这里开启事务user = userService.getUserByName(name);// 在这里提交事务}catch(Exception e){// 在这里回滚事务// 这块应该需要向外抛异常, 否则我们就无法获取异常信息了. // 至于方法声明没有添加异常声明, 是因为覆写方法, 异常必须和父类声明的异常"兼容". // 这块应该是利用的java虚拟机并不区分普通异常和运行时异常的特点.throw e;}return user;}...}
@Autowiredprivate UserService userService; // 这里spring注入的实际上是UserServiceProxy的对象private void test(){// 由于userService是UserServiceProxy的对象, 所以拥有了事务管理的能力userService.getUserByName("aa");}
Spring事务失效的其他原因
通过对Spring事务代理模式的分析,我们不难发现Spring事务失效的原因有以下几种情况:
1.private、static、final的使用
解决方法:不在类和方法上使用此类关键字
2.通过this.xxx(调用当前类的方法)
使用xml配置方式暴露代理对象.然后在service中通过代理对象AopContext.currentProxy()去调用方法。
xml配置
<aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
1 @Service2 public class HelloWorldServiceImpl implements HelloWorldService {3 @Autowired4 private BlogRepository blogRepository;5 6 @Override7 public void a(BlogEntity blogEntity) throws Exception {8 ((HelloWorldService) AopContext.currentProxy()).b(blogEntity);9 }
10
11 @Transactional(rollbackFor = Exception.class)
12 @Override
13 public void b(BlogEntity blogEntity) throws Exception {
14 blogRepository.save(blogEntity);
15 throw new Exception("错误");
16 }
17 }
3.使用默认的事务处理方式
spring的事务默认是对RuntimeException进行回滚,而不继承RuntimeException的不回滚。因为在java的设计中,它认为不继承RuntimeException的异常是”checkException”或普通异常,如IOException,这些异常在java语法中是要求强制处理的。对于这些普通异常,spring默认它们都已经处理,所以默认不回滚。可以添加rollbackfor=Exception.class来表示所有的Exception都回滚。
4.线程Thread中声明式事务不起作用
1 @Override2 public void run() {3 DefaultTransactionDefinition def = new DefaultTransactionDefinition();4 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);5 PlatformTransactionManager txManager = ContextLoader.getCurrentWebApplicationContext().getBean(PlatformTransactionManager.class);6 TransactionStatus status = txManager.getTransaction(def);7 try {8 testDao.save(entity);9 txManager.commit(status); // 提交事务
10 } catch (Exception e) {
11 System.out.println("异常信息:" + e.toString());
12 txManager.rollback(status); // 回滚事务
13 }
14 }
从上面代码可以看出,我们的解决方案是使用了编程式事务。
5.配置的事务与扫描的service不在同一个容器
在spring-framework-reference.pdf文档中有这样一段话:
<tx:annotation-driven/> only looks for @Transactional on beans in the same application context it is defined in. This means that, if you put <tx:annotation-driven/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.
这句话的意思是,<tx:annoation-driven/>只会查找和它在相同的应用上下文件中定义的bean上面的@Transactional注解,如果你把它放在Dispatcher的应用上下文中,它只检查控制器上的@Transactional注解,而不是你services上的@Transactional注解。
如果将事务配置定义在Spring MVC的应用上下文(*-servlet.xml)中,在Controller上的@Transactional注解是可以起作用的。而services上的@Transactional注解将不起作用。
详情可见:https://www.cnblogs.com/xiaojiesir/p/11058541.html
6.方法配置的事务传播行为有问题
被调用方法的事务传播行为设置为PROPAGATION_REQUIRES_NEW,导致产生两个独立的事务,外围方法抛出异常只回滚和外围方法同一事务的方法。
详情可见:https://segmentfault.com/a/1190000013341344
●史上最强Tomcat8性能优化
●阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路
●B2B电商平台--ChinaPay银联电子支付功能
●学会Zookeeper分布式锁,让面试官对你刮目相看
●SpringCloud电商秒杀微服务-Redisson分布式锁方案
查看更多好文,进入公众号--撩我--往期精彩
一只 有深度 有灵魂 的公众号0.0
Spring中同一个service中方法相互调用事务不生效问题解决方案相关推荐
- Spring中同一个service类中方法相互调用事务不生效问题解决方案
此处的this指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强,因此b方法的事务定义@Transactional(propagation = Propagation.RE ...
- Spring中同一个类中方法调用事务不生效,非事务方法调用事务方式事务不生效
我们假定在SerivceXXX中有两个方法: serviceA 非事务方法 serviceB事务方法 如果serviceA中方法定义类似如下: public void serviceA(){..... ...
- Spring中如Service有多个实现类,它怎么知道该注入哪个ServiceImpl类?
作者:zoe_java cnblogs.com/zoe-java/p/11530888.html 方法一: Controller中注入service的时候使用@Autowired自动注入,@Qual ...
- 同一个controller中同一个service不同的方法调用怎么有的会为null
今天疯狂给测试写bug的时候,发现我同一个controller中不同的方法调用同一个service竟然有的方法会为null.当时就很奇怪了,不过仔细看了下,应该是我手滑public写成private了 ...
- Spring中使用atomikos+druid实现经典分布式事务
经典分布式事务,是相对互联网中的柔性分布式事务而言,其特性为ACID原则,包括原子性(Atomictiy).一致性(Consistency).隔离性(Isolation).持久性(Durabilit) ...
- Shiro与Spring集成时,Shiro权限注解@RequiresRoles等不生效的解决方案
2019独角兽企业重金招聘Python工程师标准>>> Shiro与Spring集成时,Shiro权限注解@RequiresRoles等不生效, 这个问题着实整了好久,网上各种解决方 ...
- Java中Spring中的方法加上try catch后事务管理器失效无法回滚的情况
beab.xml配置 <bean id="dataSource" class="org.springframework.jdbc.datasource.Driver ...
- Spring中的@ Component,@ Repository和@Service批注有什么区别?
@Repository @Component , @Repository和@Service批注可以在Spring中互换使用吗,或者除了充当注解设备外,它们还提供任何特定功能吗? 换句话说,如果我有一个 ...
- Spring中的事务控制
Chapter 1. Spring中的事务控制(Transacion Management with Spring) Table of Contents 1.1. 有关事务(Transaction)的 ...
最新文章
- Java 多线程(四)—— 单例模式
- 如何判断一个程序是 32bit 还是 64bit ?
- mongodb 创建数据库权限账号,增删改查(基本操作)
- 关于Unity中OnGUI()的简单使用
- 探索 SharePoint 2013 Search功能
- python类方法和静态方法_Python 中的方法、静态方法(static method)和类方法(class method)...
- 配置单交换机VLAN划分
- ghost之后仍然中病毒----与病毒的斗争
- LeetCode之数组中的最长山脉
- 网页游戏防外挂策略。
- DSPE-PEG-cRGD,磷脂-聚乙二醇-环肽RGD,靶向穿膜肽RGD环肽供应
- JAVA Swing主题 简洁扁平化苹果风格主题
- Android 开源1:获取并解析网页信息(Jsoup)
- 吾爱破解热榜:45k 的小工具让 Windows 升级成「全面屏」!
- 百度网盘下载显示系统限制,无法下载解决
- STM32(六)——串口通信原理
- 谈谈我对于项目管理的认识!
- 三维建筑形式的生成 Graph Convolutional Network
- windows如何使用vnc,只需5步轻松掌握windows下使用vnc
- VMware workstation 6.5.1 下载