参考这个文档
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.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"/>
去掉或者细化就好了
本文探讨了在使用Spring框架实现AOP时遇到的事务代理问题,详细解释了如何通过调整配置解决只读事务导致的数据库操作受限问题。特别关注了在代理对象内部调用方法时事务拦截失效的情况,并提供了相应的解决方案。
716

被折叠的 条评论
为什么被折叠?



