参考这个文档
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"/>
去掉或者细化就好了
分享到:
相关推荐
最近想给我的框架加一种功能,就是比如给一个方法加一个事务的特性Attribute,那这个方法就会启用事务处理。给一个方法加一个缓存特性,那这个方法就会进行缓存。 这个也是网上说的面向切面编程AOP。 AOP的概念也很...
AOP事务实现 C#实现事务代码 摘自网络
java项目中 AOP事务所需要用的jar包....................................啊..........................................................
AOP思想和事务注解应用
java springAOP 事务+注释 带全部jar包! 即下即用!
手写简单实现ioc、aop事务demo,实现事务回滚,使用到了,工厂模式,动态代理
Spring AOP配置事务方法,描述了spring的事务配置,方便开发应用和数据库的连接管理。
演示了spring基于AOP代理TransactionProxyFactoryBean实现事务
aop与spring事务处理
C# AOP实现事务 AOP事务 摘自博客
NULL 博文链接:https://quicker.iteye.com/blog/674029
SpringAop配置事务管理,有两种配置方式。一种直接使用注解的方式,另外一种非注解
AOP及事务代码示例,包含数据库,可运行。。。。,,,,,
无处不在的Spring AOP事务及踩过的坑.......................
spring中aop和Synchronized锁在Spring事务管理下,导致线程不安全。
8月31日-无处不在的Spring AOP事务及踩过的坑-张飞.mp4
主要介绍了Springboot通过aop实现事务控制过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop
用springboot 集成mybatis多数据源,用aop实现的动态切换,支持事务,不会使aop动态切换失效。注意:此代码不涉及分布式事务,如果需要分布式事务 需要采取其他方案。
NULL 博文链接:https://tonl.iteye.com/blog/2093314