问题
Previously I have created a method updateRecord() in com.TestTransaction class. The updateRecord() method has a for loop to insert values into database. If there is any exception thrown inside the loop all the inserted values will rollback. This works fine and code is like below:
Inside the java class file
public class com.TestTransaction{
...
//this is a big transaction
public void updateRecord(){
for(int i=0;i<5;i++){
//insert value to database...
//...if a runtime exception thrown here,
//updateA() method will rollback as a whole transaction,
//so all updates which were done inside the loop will rollback
}
}
...
}
Inside config.xml file (Spring config file)
<bean id="masterTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="masterDataSource" />
<property name="nestedTransactionAllowed" value="true" />
</bean>
...
<aop:config proxy-target-class="true">
<aop:pointcut id="testTransactionTX" expression="execution(* com.TestTransaction.*(..))"/>
<aop:advisor pointcut-ref="testTransactionTX" advice-ref="defaultTxAdvice"/>
</aop:config>
...
<tx:advice id="defaultTxAdvice" transaction-manager="masterTxManager">
<tx:attributes>
<tx:method name="update*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
Then I decided to make code inside the loop of updateRecord() method as a separate method doUpdateRecord(). So that when doUpdateRecord() throws a RuntimeException, it only rolls back this doUpdateRecord() and all previous updates will be committed. But it seems that it fails to rollback.
Code as below:
public class com.TestTransaction{
...
//this is no longer a big transaction
public void updateRecord(){
for(int i=0;i<5;i++){
//every doUpdateRecord() call will start a new transaction
doUpdateRecord();
}
}
//this is a transaction
public void doUpdateRecord(){
//insert value to database...
//...if a runtime exception thrown here,
//it only rollback this method
}
}
Spring config file:
<bean id="masterTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="masterDataSource" />
<property name="nestedTransactionAllowed" value="true" />
</bean>
...
<aop:config proxy-target-class="true">
<aop:pointcut id="testTransactionTX" expression="execution(* com.TestTransaction.doUpdateRecord(..))"/>
<aop:advisor pointcut-ref="testTransactionTX" advice-ref="defaultTxAdvice"/>
</aop:config>
...
<tx:advice id="defaultTxAdvice" transaction-manager="masterTxManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>
Can anyone give any ideas of what is going on? Is it possible to rollback one update when a method (transaction) is called inside a loop?
回答1:
It's possibly the case I came across in this question. Calls within the same class don't pass through proxy and your pointcut logic is ignored.
回答2:
Because spring only supports aspects at method call that is knows about you spring will not be able to intercept that doUpdateRecord as it was not called against the spring managed instance of the bean. In order for the aspect to work that doUpdateRecord needs to be called against the spring bean instance because only then can spring intercept the method call and insert the transactional stuff.
Either you inject the spring bean instance of TestTransaction into test transaction itself and reference that when you call doUpdateRecord (not sure if this will work) or you move the doUpdateRecord code into another bean and call against that bean.
来源:https://stackoverflow.com/questions/8295366/how-to-define-rollback-transactions-which-are-called-inside-of-a-loop-with-sprin