我已经看过很多关于tx的文章,包括spring和AspectJ。下面是总结,比如说,我有一个服务类及其接口。
interface TestService {
void methodA();
void methodB();
}
class TestServiceImpl implements TesService {
@Transactional
void methodA() {
methodB();
}
@Transactional(propagation=Propagation.NEVER)
void methodB(){}
}还有我的配置
<tx:annotation-driven transaction-manager="jpaTxManager"/>
<bean id="jpaTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"><ref bean="entityManagerFactory"/></property>
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="testService" class="com.motherframework.plugin.test.service.TestServiceImpl">
<property name="testDAO" ref="testDAO"/>
</bean>我从某个客户端类调用testService.methodA()。根据spring的JDK动态代理使用情况,它只关心methodA()上的methodA(),而不关心methodB()上的@Transactional(propagation=Propagation.NEVER)。因此,代码以正确的事务执行并提交。如果我们使用AspectJ模式,那么它还将检查methodB()上的@Transactional(propagation=Propagation.NEVER)并引发异常。
现在我的问题是,为什么这个限制是由Spring强加的?现在有两种设计弹簧的可能性,
发布于 2012-08-03 07:06:53
是的,这是技术上的限制。当您不使用AspectJ时,事务方面是通过在实际bean类实例周围返回代理并将该代理返回/注入到其他bean来实现的。因此,当您调用testService.methodA()时,会发生以下情况(基本上):
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA()代理将围绕对testServiceImpl.methodA()的调用应用事务方面:它在之前启动事务,然后提交/回滚事务。
如果从this.methodB()调用methodA(),则会发生以下情况:
caller ---> transactionalProxy.methodA() ---> testServiceImpl.methodA() ---> testServiceImpl.methodB()而且,由于您绕过了代理,所以不能应用事务方面。
AspectJ是不同的,因为它转换TestServiceImpl的字节代码,以应用围绕各种方法调用的方面。
我不认为围绕内部方法调用应用方面是不恰当的设计。您只需注意,它只适用于字节码检测。
发布于 2014-08-12 13:24:03
这是一个技术限制(正如其他人所回答的)。如果您想让Spring检查这个,您可以这样修改您的服务:
class TestServiceImpl implements TesService {
TesService thiz; // setter left outside, assumed to be injected by Spring
@Transactional
void methodA() {
thiz.methodB();
}
@Transactional(propagation=Propagation.NEVER)
void methodB(){}
}发布于 2012-08-03 08:21:20
这里的想法是,最外层的方法知道什么是对整个事务最好的。但是,正如你注意到的,这里有一些角落的案件。
解决办法:将方法的实现移到第二个bean中,并将该bean注入TestServiceImpl。因为您将被注入代理,所以所有方法调用都会注意到注释。
您需要拆分一些方法。如果你有这种情况:
methodX() {
...code before...
methodB();
...code after...
}您可以使用回调:
methodX() {
Callable<Void> callback = new Callable<Void>() {
Void call() {
realImpl.methodB();
}
}
realImpl.methodX(callback);
}在你内心的豆子里:
void methodX(Callable<Void> callback) {
...code before...
callback();
...code after...
}https://stackoverflow.com/questions/11789857
复制相似问题