避免在Spring的事务回滚

问题描述 投票:2回答:2

假设我有下面的代码:

@Autowired
private IManager1 manager1;

@Autowired
private IManager2 manager2;

@Autowired
private IManager3 manager3;

@Transactional
public void run() {
     manager1.doStuff();
     manager2.registerStuffDone();

     manager3.doStuff();
     manager2.registerStuffDone();

     manager1.doMoreStuff();
     manager2.registerStuffDone();
}

如果有任何异常推出我想回滚一切由“doStuff()”方法来完成,但我不希望回滚由“registerStuffDone()”方法被记录的数据。

我一直在读了@Transactional注解传播选项,但我不知道如何正确地使用它们。

每个经理在内部使用Hibernate来提交更改:

@Autowired
private IManager1Dao manager1Dao;

@Transactional
public void doStuff() {
    manager1Dao.doStuff();
}

凡道看起来是这样的:

@PersistenceContext
protected EntityManager entityManager;

public void doStuff() {
    MyObject whatever = doThings();
    entityManager.merge(whatever);
}

这是我的应用程序配置:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSourcePool" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
    </property>
</bean>

<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>

想法?

java spring jpa jdbc
2个回答
2
投票

你需要2个交易,一个是要提交的东西,一个是东西回滚。

   @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor={Exception1.class, Exception2.class})
public void registerStuffDone()() {
   //code
}

然后,您的run方法将使用第一个交易,将被回滚,但registerStuffDone方法将启动,这将被COMMITED第二个事务。


1
投票

您正在使用声明式事务,并希望控制诸如程序意识。出于这个原因,你需要更多的实践和关于Spring事务定义,如传播,隔离等深刻的理解......

编程式事务管理:这意味着你有编程的帮助下管理事务。这就给了你极大的灵活性,但难以维持。 VS 声明式事务管理:这意味着你的业务代码分开的事务管理。你只用注释或基于XML配置管理事务。

也许,对于您的问题,通过编程式事务管理替代方法。

/** DataSourceTransactionManager */
    @Autowired
    private PlatformTransactionManager txManager;

    public void run() {
    try {

         // Start a manual transaction.
         TransactionStatus status = getTransactionStatus();

         manager1.doStuff();
         manager2.registerStuffDone();

         manager3.doStuff();
         manager2.registerStuffDone();

         manager1.doMoreStuff();
         manager2.registerStuffDone();

        //your condition 
        txManager.commit(status);
        //your condition 
        txManager.rollback(status);

         } catch (YourException e) {

        }       
    }    

/**
     * getTransactionStatus
     *
     * @return TransactionStatus
     */
    private TransactionStatus getTransactionStatus() {
        DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
        dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        dtd.setReadOnly(false);

        return txManager.getTransaction(dtd);
    }

注意:这并不意味着你需要经常使用像编程式事务管理的一种方法。我更喜欢混合的方法。请用简单的方式像简单的数据库服务的声明式事务,否则,只是在你的服务程序化交易控制会很容易保存您的逻辑。

© www.soinside.com 2019 - 2024. All rights reserved.