1. 需求示例
需求伪代码如下:
@ServicepublicclassJysdService{publicStringtest1(args){try{test2(args);}catch(Exception e){return"异常";}....}@Transactional(rollbackFor=Exception.class)publicIntegertest2(args){
数据库操作}}
如上代码,需要在方法1(test1)中调用方法2(test2),其中方法2启用事务。
2. spring中事务的注意事项
spring的声明式事务是基于代理模式的。其实代理模式相当简单, 就是将另一个类包裹在我们的类外面, 在调用我们创建的方法之前, 先经过外面的方法, 进行一些处理, 返回之前, 再进行一些操作。
2.1 声明事务的方法不能用private、static、final修饰
2.2 调用事务方法时,不能用this.xxx
原因是由于JDK的动态代理。 在SpringIoC容器中返回的调用的对象是代理对象而不是真实的对象,只有被动态代理直接调用的才会产生事务。这里的this是(JysdService)真实对象而不是代理对象,所以事务会失效,不会回滚。
同理,上面的示例代码中,在方法1中调用方法2,实际上就是this.xxx调用方式,所以这样方法2的事务会失效。
2.3 不要用try在事务方法内部处理异常,导致没有异常抛出
例如
@Transactional(rollbackFor=Exception.class)publicStringtest2(){try{
数据入库}catch(Exception e){return"异常";}return"";}
上面这种方法事务是不会回滚的,因为你在方法内部已经把异常处理掉了,所以代理对象是捕获不到异常的,也就不会回滚。
你可以针对异常做一些处理,比如打印日志等,但是一定要把异常抛出去,例如
@Transactional(rollbackFor=Exception.class)publicStringtest2()throwsException{try{
数据入库}catch(Exception e){
logger.info(e.toString());thrownewException();// 抛出异常}return"";}
3. 针对同一个类中其他方法调用时,事务不生效的解决方案
不要在同一个类里面直接调用事务方法,即不要在service类的方法1中直接调用方法2(事务),这样是不会生效的。事务方法必须从外部调用。例如可以直接在controller中调用service中的事务方法。或者在service中创建一个当前类的外部代理对象,然后通过这个代理对象来调用当前类中的事务方法。
外部代理解决方法示例:
//解决方法publicStringtest1(args){try{JysdService proxy=(JysdService)AopContext.currentProxy();
proxy.test2(atrs);}catch(Exception e){return"异常";}....}
但是我这样使用时报错了:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available
解决方法参考(亲测有效):
JysdService jysdService=SpringUtil.getBean(this.getClass());//SpringUtil工具类见下面代码
SpringUtil.java
@ComponentpublicclassSpringUtilimplementsApplicationContextAware{privatestaticApplicationContext applicationContext=null;@OverridepublicvoidsetApplicationContext(ApplicationContext applicationContext)throwsBeansException{SpringUtil.applicationContext= applicationContext;}publicstatic<T>TgetBean(Class<T> cla){return applicationContext.getBean(cla);}publicstatic<T>TgetBean(String name,Class<T> cal){return applicationContext.getBean(name, cal);}publicstaticObjectgetBean(String name){return applicationContext.getBean(name);}publicstaticStringgetProperty(String key){return applicationContext.getBean(Environment.class).getProperty(key);}}
参考文章
https://blog.csdn.net/mameng1988/article/details/85548812