簡體   English   中英

如何回滾使用JPA實體偵聽器調用的事務

[英]How to rollback transaction invoked with jpa entity listeners

我正在使用jpa,spring數據和實體偵聽器來精確地在postUpdate,postPersist,PostRemove上審計我的實體

這是我的實體偵聽器類的偽代碼

public class EntityListener extends AuditingEntityListener {

@PostUpdate
public void postPersist(Object auditedEntity) {
    writer.saveEntity(auditedEntity,"UPDATE");
}

這是Writer類的偽代碼

public class Writer {

@Async
public void saveEntity(Object auditedEntity, String action) {
    try {

//some code to prepare the history entity

        historyDAO.save(entity);

    } catch (Exception e) {

    }
} 

當在Writer類中引發異常時,會更新或插入auditedEntity,但是我存儲審計操作的historyEntity不會

問題是我需要在另一個線程中調用性能問題(@Async)的saveEntity方法,但是在這種情況下,將打開一個新事務,而不是先前打開的事務

我該如何解決這兩個事務的前滾問題,以便當引發異常時,historyEntity和auditedEntity都不會持久化

據我所知,你要回滾兩個孩子當異常是從內拋出父事務Writer.saveEntity

問題在於,具有原始事務的線程在將事務標記為已提交之前仍需要等待所有這些復雜的操作完成。 您也不能輕易跨多個線程進行事務處理。

可能要做的唯一一件事就是可以並行運行生成歷史實體的邏輯,然后在事務提交之前將它們全部保存。

我可以想到的一種實現方法是使用Hibernate攔截器:

public class AuditInterceptor extends EmptyInterceptor {
    private List<Callable<BaseEntity>> historyEntries;
    private ExecutorService executor;
    ...

    public void beforeTransactionCompletion(Transaction tx) {
        List<Future<BaseEntity>> futures = executor.invokeAll(historyEntries);
        if (executor.awaitTermination(/* some timeout here */)) {
            futures.stream().map(Future::get).forEach(entity -> session.save(object));
        } else {
            /* rollback */
        }
    }
}

然后,您的偵聽器代碼變為:

@PostUpdate
public void postPersist(Object auditedEntity) {
    interceptor.getHistoryEntries().add(new Callable<BaseEntity> {
        /* history entry generation logic goes here */
    });
}

(請注意,上面的代碼已大大簡化,可以使用任何其他異步執行API,其基本思想是需要在AuditInterceptor.beforeTransactionCompletion中進行AuditInterceptor.beforeTransactionCompletion ,等待所有歷史記錄條目生成)

但是,我強烈建議您不要使用上述技術,因為它相當復雜且容易出錯。

如果您在這里查看: https : //docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/events/Events.html ,您會發現Hibernate攔截器具有更有趣的方法,可以幫助您收集審核信息,也許您的實現可以利用它們,從而可以完全避免使用復雜的邏輯(Hibernate已經跟蹤了各個實體字段的更改,因此您可以免費獲得該信息)。

為什么要重新發明輪子? 如果您進行更深入的研究,您會發現Hibernate Envers模塊( http://hibernate.org/orm/envers/ ,適用於JPA和純Hibernate),可為您提供開箱即用的業務審計。 Envers已經研究了上述機制,因此希望性能問題能夠解決。

最后說明:您是否測量了生成歷史記錄條目所花費的時間? 我猜想執行for循環和if語句可能比數據庫訪問操作便宜。 如果我是您, 除非絕對確定這是性能瓶頸所在,否則我將不會執行上述任何操作

暫無
暫無

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

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