文档章节

【每日提高之声明式事物】spring声明式事务 同一类内方法调用事务失效

卯金刀GG
 卯金刀GG
发布于 2018/08/01 14:06
字数 1112
阅读 54
收藏 2

【问题】

       Spring的声明式事务,我想就不用多介绍了吧,一句话“自从用了Spring AOP啊,事务管理真轻松啊,真轻松;事务管理代码没有了,脑不酸了,手不痛了,一口气全配上了事务;轻量级,测试起来也简单,嘿!”。不管从哪个角度看,轻量级声明式事务都是一件解放生产力的大好事。所以,我们“一直用它”。

      不过,最近的一个项目里,却碰到了一个事务管理上的问题:有一个服务类,其一个声明了事务的方法,里面做了三次插入SQL操作,但是在后面出错回滚时,却发现前面插入成功了,也是说,这个声明了事务的方法,实际上并没有真正启动事务!怎么回事呢?难道Spring的声明式事务失效了?

 

【分析】

     这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。

     我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。

Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:

现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:

因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。

    

      而这种结果,会造成什么影响呢:

      1:内部调用时,被调用方法的事务声明将不起作用

      2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中

      3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。

      4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。

【解难】

     

      问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:

使用代理

1、Proxy.insertAAA() 代理对象加了事物,这样就可以增强事物。

public void a() {  

aopProxy.b();//即调用AOP代理对象的b方法即可执行事务切面进行事务增强  

}  

判断一个Bean是否是AOP代理对象可以使用如下三种方法:

AopUtils.isAopProxy(bean)        : 是否是代理对象;

AopUtils.isCglibProxy(bean)       : 是否是CGLIB方式的代理对象;

AopUtils.isJdkDynamicProxy(bean) : 是否是JDK动态代理方式的代理对象;

  1. <aop:aspectj-autoproxy expose-proxy="true"/><!—注解风格支持-->  
  2. <aop:config expose-proxy="true"><!—xml风格支持-->   

修改我们的代码

this.b();-----------修改为--------->((AService) AopContext.currentProxy()).b();

 

在使用的过程中,提示错误:

关于AOP无法切入同类调用方法的问题给方式使用注解

@Transactional(propagation = Propagation.REQUIRED,
    isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)

文章参考:

https://blog.csdn.net/dapinxiaohuo/article/details/52092447

https://blog.csdn.net/aya19880214/article/details/50640596

© 著作权归作者所有

卯金刀GG
粉丝 27
博文 261
码字总数 70945
作品 0
昌平
程序员
私信 提问
@Transaction必知必会

1. Spring事务的基本原理 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编码式和声明式的两种方式。编程式事务指的是通过编码方式...

maskwang520
2018/04/15
0
0
Java框架 Spring 核心机制

概念 轻量级的(面向切面AOP)、(IOC控制反转)容器框架。 Spring优点 1.降低组件之间的耦合性 2.专注于自己业务逻辑,统一的行为(日志、安全等)抽象出来统一处理 3.易于单元测试 4.方...

java知识分子
2018/09/28
0
0
Spring事务——使用TransactionProxyFactoryBean创建事务代理

Spring同时支持编程式事务策略和声明式事务策略,大部分时候,我们都推荐采用声明式事务策略。使用声明式事务策略的优势十分明显: 声明式事务能大大降低开发者的代码书写量,而且声明式事务...

摆渡者
2014/03/26
0
0
spring 声明事物

采用的基本搭建环境:SpringMVC、MyBatis、MySQL、tomcat Spring事务管理分解了传统的全局事务管理和本地事务管理的劣势,使得在任何环境中都可以使用统一的事务管理模型,你可以写一次代码,...

訫犫
2016/01/15
70
0
分析 Spring 的编程式事务管理及声明式事务管理(转)

开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务。通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之。 先决条件...

君辰
2015/07/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

DevExpress-winform实现打印功能

创建Windows窗体,拖入richEdtControl(或者GridControl)+打印按钮(button) 双击打印,创建click事件,直接用richEdtControl1调用ShowPrintPreview()方法 private void btnPrint_Click(o...

元歌
21分钟前
0
0
Lucene

Lucene 简介: Lucene是apache下的一个开源的全文检索引擎工具 1.1.全文检索:先分词创建索引,再搜索(分词:就是将一个句子分成多个单词) 全文检索的流程分为两大部分:索引流程、搜索流程...

klmkom
21分钟前
0
0
SpringBoot2.0高级案例(03):集成 JavaMail ,实现异步发送邮件

本文源码码云地址:知了一笑https://gitee.com/cicadasmile/middle-ware-parent 一、JavaMail的核心API 1、API功能图解 2、API说明 (1)、Message 类: javax.mail.Message 类是创建和解析邮...

知了一笑
21分钟前
15
0
Andrew Ng 机器学习鸡尾酒音频分离算法解析

[w,s,v] = svd((repmat(sum(x.*x,1),size(x,1),1).*x)*x'); 在学习机器学习的课程过程中,ng用一行代码实现了音频分离的效果,这里对这行代码进行解析。 [x1, Fs1] = audioread('E:\sounds\f...

gdxz110
25分钟前
0
0
动漫人物阴影绘画技巧

动漫人物阴影绘画技巧?我们在上色的时候,对色彩的使用都大致了解,但是却不知道怎么画阴影。如果这是在现实日常生活中会看到的,但是要想画出来的话就很难了,下面就让我们一起来看看画阴影...

设绘嗨
26分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部