簡體   English   中英

避免在春季進行交易回滾

[英]Avoid Transaction rollback in Spring

假設我有下面的代碼:

@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注釋的傳播選項,但是我不知道如何正確使用它們。

每個經理在內部使用hiberante提交更改:

@Autowired
private IManager1Dao manager1Dao;

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

dao看起來像這樣:

@PersistenceContext
protected EntityManager entityManager;

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

這是我的applicationContext配置:

<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"/>

想法?

您需要2個事務,一個事務要提交,另一個事務要回滾。

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

然后,您的run方法將使用第一個事務並將其回滾,但是registerStuffDone方法將啟動將要提交的第二個事務。

您正在使用聲明式事務,並希望像程序意義那樣進行控制。 因此,您需要更多實踐和對Spring事務定義的深入理解,例如PROPAGATION,ISOLATION等。

程序化交易管理:這意味着您可以通過編程來管理交易。 這為您提供了極大的靈活性,但是很難維護。
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);
    }

注意:這並不意味着您需要始終使用一種方法,例如程序化事務管理。 我更喜歡混合方法。 對於簡單的數據庫服務,請使用聲明式事務之類的簡單方法,否則,只需在服務中使用程序化事務進行控制即可輕松保存邏輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM