`
newslxw
  • 浏览: 208787 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

AOP 事务缺陷

 
阅读更多

参考这个文档

http://liuu.iteye.com/blog/422810

 

http://www.51cto.com/specbook/223/39480.htm

 

http://www.iflym.com/index.php/code/proxy-created-of-subclass-extended-proxied-class-by-spring.html

 

http://www.iflym.com/index.php/code/proxy-method-intercept-of-subclass-extended-proxied-class-by-spring.html

 

http://www.iteye.com/problems/71797

 

http://www.iteye.com/topic/40553

 

http://www.redsaga.com/spring_ref/2.5/html/aop-api.html

 

http://japi.iteye.com/blog/285800

 

或许按照回复的办法,把参考文档中的两个方法放到不同类中。

很不幸,我也遇到了这个问题。

但是按照作者的方法,修改aop:config如下:

    <aop:config proxy-target-class="true">

       <aop:pointcut id="allServiceMethod" expression="execution(* *..service.*Service.*(..)) " />
      <aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />

  </aop:config>

其中service包下的是接口,具体实现在service.spring包下面。

修改后还是不行。

但改成这样就好了:

<aop:config>

<aop:pointcut id="allServiceMethod" expression="execution(* *..service.*Service.*(..)) and execution(* *..service.*.*Service.*(..))" />
<aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />

 </aop:config>

 

也就是在接口和实现类都声明在事务中。

 如果只是在声明接口或者实现类单方面加都不行。

修改后虽然能写数据库,但是事务不生效!!!很奇怪的问题!!!!

 

我的情况如下:

action调用service.A  ;serviceA调用service.B;

事务设置采用声明式事务

其中service.A的方法属于只读事务;B方法属于读写事务;然后B又调用service2.B,真正写数据库的是service2.B。

调用时报错,只读事务,不能修改数据。

查看堆栈发现,代理只在调用A时加了事务拦截,在A调用B是没加事务拦截;

堆栈大概如下,注意红色字体是连在一次调用,中间没有任何拦截:

 at xxx.service.spring.ServiceImpl.B(ServiceImpl.java:1245)
 at xxx.service.spring.ServiceImpl.A(ServiceImpl.java:1555)

 at xxx.service.spring.ServiceImpl$$FastClassByCGLIB$$5bad9769.invoke(<generated>)
 at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
 at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:700)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
 at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:635)
 at xxx.action$$EnhancerByCGLIB$$f76d57d.xxx(<generated>)

 

 

 

如果是required,则事务依旧使用原来的事务,所以A只读,导致B只读,把service2.B改成REQUIRED_NEW就好了但没什么特殊要求都应该使用REQUIRED。

这个问题引起的原因是这个配置

 <tx:method name="*" propagation="REQUIRED" read-only="true"/>

导致A变成只读,范围太大了。

上面改后,service.B中依旧是只读事务。

 

测试发现AOP不能嵌套,不管JDK还是cglib都一样,如果同一对象OBJ的第一个函数A没有使用事务,那么A里面调用的OBJ.B方法,尽管B方法已经声明了事务,但一样不生效,因为AOP没有对A调用B是做拦截,也不可能做,B在OBJ中调用,不是在代理中调用,代理没法做。跨类到可以。

只读原因分析:

所以service.A只读事务,导致service.A调用B时,没经过AOP事务拦截,也就是service.A和service.B在同一个事务中,B就是只读事务,而当B调用service2.B时,如果service2.B是REQUIRED时,尽管service2.B的AOP拦截生效,但是REQUIRED命令service2.B直接使用已有事务,导致service2.B中也是只读事务。

 

 <tx:method name="*" propagation="REQUIRED" read-only="true"/>

去掉或者细化就好了

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics