【问题标题】:Running method in its own datasource transaction when called from other service which is using datasoure-2 transaction从使用 datasoure-2 事务的其他服务调用时在其自己的数据源事务中运行方法
【发布时间】:2016-07-02 00:12:58
【问题描述】:

我有一个使用 2 个不同数据源的场景。

数据源 1 服务类(启用事务)调用数据源 2 服务类方法(启用事务但使用数据源 2)

代码如下。我的要求是,当我们在此层次结构中调用时,如何在单独的事务中运行 persistOneByOne()。如果发生异常,请不要保留该记录,但由于它在 for 循环中继续处理其他记录。 我如何实现这种行为。

// 服务类 2 使用由 aop 启用的事务处理的 datasource-1

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() 在其自己的事务中运行。如果发生异常回滚该单行。

【问题讨论】:

    标签: transactions spring-transactions


    【解决方案1】:

    我认为您的方案适合基于保存点的数据库交互。 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 注释而不是事务管理器来注释方法/类。文档: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();
           } 
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多