我有一个使用2个不同数据源的场景。
数据源1服务类(启用了事务)调用数据源2服务类方法(启用了事务但是使用了datasource2)
代码如下。我的要求是当我们在这个层次结构中调用时,如何在单独的事务中运行persistOneByOne()。如果发生exeption,则不要保留该记录,但是因为它的for循环继续处理其他记录。 我如何实现这种行为。
//服务类2使用数据源-1,它是由aop
启用的事务处理public class DataSource1ServiceClass1{
DataSource2OtherServiceClass service2;
public void processData(){
service2.prepareAndPeristData();
}
}
//服务类2使用一个名为datasource-2的不同数据源,该数据源也是由aop启用的事务
public class DataSource2OtherServiceClass{
public void prepareAndPeristData(){
try{
for(int i=0;i<10;i++)
{
// pre processing before persisting a single record
persistOneByOne();
}
}catch (Exception e){
log.error("Error occurred.. so didn't persist record as expected"};
}
public void persistOneByOne()
{
dao.persist();
}
}
配置xml文件:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allServices"
expression="execution(* .service.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="allServices" />
</aop:config>
<bean id="txManager2"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="otherDataSource" />
</bean>
<tx:advice id="txAdvice2" transaction-manager="txManager2">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="allOtherServices"
expression="execution(* .service2.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice2" pointcut-ref="allOtherServices" />
</aop:config>
如何实现persistOneByOne()在自己的事务中运行。如果发生异常,则回滚该行。
答案 0 :(得分:0)
我认为您的方案符合基于保存点的数据库交互。 Spring通过NESTED
传播支持它。
如果您将嵌套传播建议应用于代码中的persistOneByOne()
方法;它会在每次执行该方法时创建一个保存点,如果发生重复,它将回滚到最后一个保存点。然后继续下一步。
从技术上讲,您可以通过将REQUIRES_NEW
传播建议应用于您的方法来实现,但每次调用它时都会打开一个新事务。这被认为是一种不好的做法,因为它会破坏您的数据库大量交易的情况。
此外,您可以从txManager2
的集合中删除事务建议,然后使用@Transactional
注释而不是使用transactionManager注释方法/类。 Doc:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html
您需要在配置中添加:
<tx:annotation-driven proxy-target-class="true"/>
有了这个,你的课将看起来像这样:
public class DataSource2OtherServiceClass{
@Transactional(rollbackFor = {Exception.class}, propagation=PROPAGATION.REQUIRES_NEW, transactionManager="txManager2")
public void prepareAndPeristData(){
try{
for(int i=0;i<10;i++)
{
// pre processing before persisting a single record
persistOneByOne();
}
}catch (Exception e){
log.error("Error occurred.. so didn't persist record as expected"};
}
@Transactional(rollbackFor = {Exception.class}, propagation=PROPAGATION.NESTED, transactionManager="txManager2")
public void persistOneByOne()
{
dao.persist();
}
}