从使用datasoure-2事务的其他服务调用时,在自己的数据源事务中运行方法

时间:2016-06-23 10:09:34

标签: transactions spring-transactions

我有一个使用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()在自己的事务中运行。如果发生异常,则回滚该行。

1 个答案:

答案 0 :(得分:0)

我认为您的方案符合基于保存点的数据库交互。 Spring通过NESTED传播支持它。

如果您将嵌套传播建议应用于代码中的persistOneByOne()方法;它会在每次执行该方法时创建一个保存点,如果发生重复,它将回滚到最后一个保存点。然后继续下一步。

从技术上讲,您可以通过将REQUIRES_NEW传播建议应用于您的方法来实现,但每次调用它时都会打开一个新事务。这被认为是一种不好的做法,因为它会破坏您的数据库大量交易的情况。

您可以查看详细信息:http://www.marcobehler.com/make-it-so-java-db-connections-and-transactions-html/spring-transactional-propagation-propagation-nested.html

此外,您可以从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();
       } 
}