簡體   English   中英

如何知道回滾已執行? [@Transactional]

[英]How to know that rollback has been executed ? [@Transactional]

我有以下情況:

我正在遍歷我的Affiliate實體,對於每個實體,我都需要在一個唯一的事務中保留和更新數據。 因此,我有一個服務,該服務的方法使用Spring @Transactional注釋(在其中創建和更新數據)注釋,但是我不知道如何查看該交易已被會員回滾?

我想知道,對於特殊Affiliate ,交易已回滾並從我的服務中檢索自定義錯誤代碼。

這是我在使用Spring之前的服務:

public void savePostingPaymentDetails(List<Posting> postingsToUpdate, List<PaymentPostingDetail> detailsToInsert, Payment payment) {
    logger.info("DB ACCESS : INSERT PAYMENT DETAILS & UPDATE POSTINGS");
    long begin = System.nanoTime();

    this.em.getTransaction().begin();

    try {
        // TEST
        // 1 - Save Payments
        this.em.persist(payment);

        // 2 - Save Details
        for (PaymentPostingDetail ppd : detailsToInsert) {
            this.em.persist(ppd);
        }

        // 3 - Update Postings
        for (Posting p : postingsToUpdate) {
            if(p.getSignature() != null)
            {
                p.getSignature().setModification("withholding-tax.pay", new Date());
            }
            else
            {
                logger.error("The Posting with id = " + p.getIdentifier() + " has no PersistenceSignature ?!");
            }
            this.em.merge(p);
        }
    }
    catch (Exception e)
    {
        logger.error("Unexpected error on saving/updating the DB.", e);

        this.em.getTransaction().rollback();
        logger.info("RollBack done.");

        e.printStackTrace();
        System.exit(JobStatus.ABNORMAL_END_OF_EXECUTION_ERROR.getCode());
    }

    this.em.getTransaction().commit();
    logger.info("Details inserted & Postings updated.");

    long end = System.nanoTime();
    logger.info("Execution time = " + ((end-begin) / 1000000) + " milliseconds.");
    logger.info("----------------------------------------------------------");
}

現在我有這個:

@Transactional
public void savePostingPaymentDetails(List<Posting> postings, List<PaymentPostingDetail> paymentDetails, Payment payment)
{
    logger.info("DB ACCESS : INSERT PAYMENT DETAILS & UPDATE POSTINGS");
    long begin = System.nanoTime();

    this.paymentRepository.save(payment);
    this.ppdRepository.save(paymentDetails);

    for(Posting p : postings){
        if(p.getSignature() != null)
        {
            p.getSignature().setModifiedAt(LocalDate.now());
            p.getSignature().setModifiedBy(PayCopyrightWithholdingTaxProcess.SIGNATURE);
        }
        else{
            p.setSignature(new PersistenceSignature(LocalDate.now(), PayCopyrightWithholdingTaxProcess.SIGNATURE));
        }
        this.postingRepository.save(p);
    }

    long end = System.nanoTime();
    logger.info("Execution time = " + ((end-begin) / 1000000) + " milliseconds.");
    logger.info("----------------------------------------------------------");
}

但是,如果事務已回滾,我如何返回一個特殊的整數(而不是System.exit() )呢?

您可以使用偵聽器( @TransactionalEventListener )通知回退的事務(偵聽器可以綁定到事務的不同階段)。 有關更多信息,請參見https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html的 16.8節(需要Spring> = 4.2)

有一種叫做用戶管理的事務(UMT)和容器管理的事務(CMT)的東西,當您使用@Transactional時,實際上是將事務管理委托給您的Spring容器(CMT),它負責例如為您打開和關閉事務。 當拋出unchecked Exception (如NullPointerExceptionRuntimeException )時,它將自動回滾。 對於檢查的異常,您必須指定應該發生@Transactional(rollbackFor=myCheckedException.class)

您還可以偵聽,使用TransactionalEventListener觀察事務如何進行,並使用此處顯示的一些AOP偵聽代碼做出反應。 但是您最終並沒有管理事務,Spring正在為您做。 發生特殊情況時,客戶端代碼無法對某些自定義代碼做出反應 ,因為事務的管理委托給Spring。

因此,您必須依靠用戶管理的事務,在該事務中您可以打開事務,提交事務並在發生回滾的情況下做出反應。 這正是UMT的目的: 完全控制您的交易

從您的舊代碼中,您可能會得到類似:

public int savePostingPaymentDetails(List<Posting> postingsToUpdate, List<PaymentPostingDetail> detailsToInsert, Payment payment) {

    int returnCode = 1 // 1 -> "success" , 0 -> "failure"

    logger.info("DB ACCESS : INSERT PAYMENT DETAILS & UPDATE POSTINGS");
    long begin = System.nanoTime();
    long end = 0;

    this.em.getTransaction().begin();

    try {
        // TEST
        // 1 - Save Payments
        this.em.persist(payment);

        // 2 - Save Details
        for (PaymentPostingDetail ppd : detailsToInsert) {
            this.em.persist(ppd);
        }

        // 3 - Update Postings
        for (Posting p : postingsToUpdate) {
            if(p.getSignature() != null)
            {
                p.getSignature().setModification("withholding-tax.pay", new Date());
            }
            else
            {
                logger.error("The Posting with id = " + p.getIdentifier() + " has no PersistenceSignature ?!");
            }
            this.em.merge(p);
        }
        this.em.getTransaction().commit();
        end = System.nanoTime();
    }
    catch (Exception e)
    {
        returnCode = 0;
        logger.error("Unexpected error on saving/updating the DB.", e);

        this.em.getTransaction().rollback();
        logger.info("RollBack done.");

        // e.printStackTrace();
         System.exit(JobStatus.ABNORMAL_END_OF_EXECUTION_ERROR.getCode());
        return returnCode;
    }

    //this.em.getTransaction().commit();
    logger.info("Details inserted & Postings updated.");

    //long end = System.nanoTime();
    logger.info("Execution time = " + ((end-begin) / 1000000) + " milliseconds.");
    logger.info("----------------------------------------------------------");
    return  returnCode = 1;
}

PS :順便說一句,最佳實踐是讓您在提交失敗時引發異常 ,而不是特殊代碼。

您的新方法簽名可能是:

public void savePostingPaymentDetails(List<Posting> postingsToUpdate, List<PaymentPostingDetail> detailsToInsert, Payment payment) 
throws MyFailedDbOperationException, OtherException {

}

並在您的catch塊上拋出異常

catch (Exception e)
{
    logger.error("Unexpected error on saving/updating the DB.", e);

    this.em.getTransaction().rollback();

    logger.info("RollBack done.");
    throw MyFailedDbOperationException("my db operation failed");
}

暫無
暫無

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

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