一个Service方法调用Spring事务的内部多个方法
package com.bluesky;
public interface FooServiceIface {
public void insertA();
public void insertB();
}
package com.bluesky;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class FooServiceImpl extends JdbcDaoSupport implements FooServiceIface {
public void insertA() {
this.getJdbcTemplate().execute("insert student(name) values('stuA')");
insertB();
int i=10/0;
}
public void insertB() {
this.getJdbcTemplate().execute("insert student(name) values('stuB')");
}
}
public class Client {
public static void main(String[] args) {
ApplicationContext appContxt = new ClassPathXmlApplicationContext("applicationContext.xml");
FooServiceIface fService= (FooServiceIface)appContxt.getBean("fooService");
fService.insertA();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="fooService" class="com.bluesky.FooServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insertA" propagation="REQUIRED" />
<tx:method name="insertB" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="interceptorPointCuts" expression="execution(* com.bluesky.*Service*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>
抱歉,代码很复杂
当我运行客户端时,调试日志显示:
21:44:19,546 DEBUG TransactionSynchronizationManager:183 - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ba86ef] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1b9658e] to thread [main] 21:44:19,546 DEBUG TransactionSynchronizationManager:258 - Initializing transaction synchronization 21:44:19,547 DEBUG TransactionInterceptor:362 - Getting transaction for [com.bluesky.FooServiceImpl.insertA] 21:44:19,547 DEBUG JdbcTemplate:416 - Executing SQL statement [insert student(name) values('stuA')] 21:44:19,592 DEBUG JdbcTemplate:416 - Executing SQL statement [insert student(name) values('stuB')] 21:44:19,594 DEBUG TransactionInterceptor:406 - Completing transaction for [com.bluesky.FooServiceImpl.insertA] after exception: java.lang.ArithmeticException: / by zero 21:44:19,594 DEBUG RuleBasedTransactionAttribute:130 - Applying rules to determine whether transaction should rollback on java.lang.ArithmeticException: / by zero 21:44:19,594 DEBUG RuleBasedTransactionAttribute:147 - Winning rollback rule is: null 21:44:19,595 DEBUG RuleBasedTransactionAttribute:152 - No relevant rollback rule found: applying default rules 21:44:19,595 DEBUG DataSourceTransactionManager:938 - Triggering beforeCompletion synchronization 21:44:19,595 DEBUG DataSourceTransactionManager:843 - Initiating transaction rollback 21:44:19,596 DEBUG DataSourceTransactionManager:279 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@167f4bf] 21:44:19,598 DEBUG DataSourceTransactionManager:967 - Triggering afterCompletion synchronization 21:44:19,598 DEBUG TransactionSynchronizationManager:316 - Clearing transaction synchronization
我发现当调用 insertA()
方法时,此方法启动一个事务,当代码到达 insertB(),没有启动事务。
是否有什么我没有配置或有任何问题我犯了错误
我的意图是当 insertA()
调用 insertB(
) 时有一个 REQUIRES_NEW
交易开始。
package com.bluesky;
public interface FooServiceIface {
public void insertA();
public void insertB();
}
package com.bluesky;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class FooServiceImpl extends JdbcDaoSupport implements FooServiceIface {
public void insertA() {
this.getJdbcTemplate().execute("insert student(name) values('stuA')");
insertB();
int i=10/0;
}
public void insertB() {
this.getJdbcTemplate().execute("insert student(name) values('stuB')");
}
}
public class Client {
public static void main(String[] args) {
ApplicationContext appContxt = new ClassPathXmlApplicationContext("applicationContext.xml");
FooServiceIface fService= (FooServiceIface)appContxt.getBean("fooService");
fService.insertA();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="fooService" class="com.bluesky.FooServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="insertA" propagation="REQUIRED" />
<tx:method name="insertB" propagation="REQUIRES_NEW" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="interceptorPointCuts" expression="execution(* com.bluesky.*Service*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
</aop:config>
</beans>
Sorry for the Complicated code
When i run Client blow debug logs are showing:
21:44:19,546 DEBUG TransactionSynchronizationManager:183 - Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ba86ef] for key [org.springframework.jdbc.datasource.DriverManagerDataSource@1b9658e] to thread [main] 21:44:19,546 DEBUG TransactionSynchronizationManager:258 - Initializing transaction synchronization 21:44:19,547 DEBUG TransactionInterceptor:362 - Getting transaction for [com.bluesky.FooServiceImpl.insertA] 21:44:19,547 DEBUG JdbcTemplate:416 - Executing SQL statement [insert student(name) values('stuA')] 21:44:19,592 DEBUG JdbcTemplate:416 - Executing SQL statement [insert student(name) values('stuB')] 21:44:19,594 DEBUG TransactionInterceptor:406 - Completing transaction for [com.bluesky.FooServiceImpl.insertA] after exception: java.lang.ArithmeticException: / by zero 21:44:19,594 DEBUG RuleBasedTransactionAttribute:130 - Applying rules to determine whether transaction should rollback on java.lang.ArithmeticException: / by zero 21:44:19,594 DEBUG RuleBasedTransactionAttribute:147 - Winning rollback rule is: null 21:44:19,595 DEBUG RuleBasedTransactionAttribute:152 - No relevant rollback rule found: applying default rules 21:44:19,595 DEBUG DataSourceTransactionManager:938 - Triggering beforeCompletion synchronization 21:44:19,595 DEBUG DataSourceTransactionManager:843 - Initiating transaction rollback 21:44:19,596 DEBUG DataSourceTransactionManager:279 - Rolling back JDBC transaction on Connection [com.mysql.jdbc.JDBC4Connection@167f4bf] 21:44:19,598 DEBUG DataSourceTransactionManager:967 - Triggering afterCompletion synchronization 21:44:19,598 DEBUG TransactionSynchronizationManager:316 - Clearing transaction synchronization
I found that when invoked insertA()
method , this method start a transaction, when the code arrive insertB()
, there is not transaction for starting.
Is there anything did i not configured or any concern i made mistaken
My intention is to when insertA()
call insertB(
) there is an REQUIRES_NEW
transaction start.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
KLE 关于重构代码的建议是正确的,但至于为什么它不起作用,Spring AOP 使用 JDK动态代理默认提供AOP。这意味着当您将服务注入某些东西时,真正注入的是实现您的服务接口的 Proxy 实例。当在此代理上调用方法时,它会在委托给实际服务实例之前运行事务代码。不过,一旦控制流位于您的服务内部,通过 this.foo() 调用另一个方法(即使
this
是隐式的)也只会调用同一实例上的方法: 你的服务。它不会返回到代理,这是唯一了解事务的东西。 如果你切换了 使用 AspectJ 构建或加载时字节码编织,那么您可以执行此操作,并且它将按预期工作,因为事务调用代码将直接编织到您的服务代码中,而不是存在于单独的对象中。KLE's advice about refactoring your code is right on the money, but as for why it's not working, Spring AOP uses JDK dynamic proxies by default to provide AOP. That means that when you inject your service into something, what's really getting injected is a Proxy instance that implements your service interface. When a method is invoked on this proxy, it runs the transaction code before delegating to your actual service instance. Once the control flow is inside your service, though, calling another method via
this.foo()
(even if thethis
is implicit) just invokes a method on that same instance: your service. It doesn't go back to the proxy, which is the only thing that knows about transactions. If you switched to build- or load-time bytecode weaving with AspectJ, then you could do this, and it would work as expected, since the transaction-invoking code would be woven directly into your service code instead of living in a separate object.我理解你的问题。有一些技术上复杂的方法可以让它发挥作用,但我们通常认为它们不值得。我建议另一种简单而强大的方法,它实际上可以改进您的代码。
不要将它们放在同一个 Spring bean 上,而是将它们放在两个不同的 Bean 上,B 被注入到 A 中。
我知道我不会回答你的问题,但想想优点:
I understand your problem. There are some technically complex ways to get it work, but we don't usually consider they are worth it. I suggest another approach, simple and powerful, that actually improves your code.
Instead of having them on the same Spring bean, have them on two different Beans, B being injected into A.
I known I'm not answering your question, but think about the advantages :
KLE的回答是中肯的建议。为了完成图片,有一个解决方法,但它破坏了 AOP 所代表的一切:
参考:
AopContext
javadocKLE's answer is solid advice. Just to complete the picture, there is a workaround, but it breaks everything AOP stands for:
Reference:
AopContext
javadoc