2012-08-27 56 views
3

我實現了一個Hibernate的事件監聽器,像這樣:Hibernate的事件監聽器 - 回滾

public class AuditListener implements PostInsertEventListener { 
    private static final long serialVersionUID = -966368101369878522L; 

    @Override 
    public void onPostInsert(PostInsertEvent event) { 
    if (event.getEntity() instanceof Auditable) { 
     StatelessSession session = null; 
     try { 
     session = event.getPersister().getFactory().openStatelessSession(); 
     Auditable auditableEntity = (Auditable)event.getEntity(); 
     session.beginTransaction(); 
     session.insert(new AuditTrail(auditableEntity.getClass().getSimpleName(), 
      auditableEntity.getId(), auditableEntity.getStatus(), 
      auditableEntity.getLastModified())); 
     session.getTransaction().commit(); 
     } catch (HibernateException he) { 
     System.out.println("Horrible error: " + he.getMessage()); 
     session.getTransaction().rollback(); 
     } finally { 
     if (session != null) { 
      session.close(); 
     } 
     } 
    } 
    } 
} 

它所做的就是將任何Auditable對象後立即插入一個AuditTrail對象到數據庫中。

我遇到的問題是在交易過程中有任何異常情況持續存在Auditable對象時:事務回滾,但仍插入AuditTrail記錄。

我試圖把這樣的:

StatelessSession session = event.getPersister().getFactory().openStatelessSession(); 

進入這個:

Session session = event.getSession(); 

但是,當我嘗試使用它會導致該消息在Session is closed結束的堆棧跟蹤。

問題似乎是事件在事務中間觸發,在導致回滾的異常情況之前觸發,並且由於事件偵聽器必須使用自己的會話,所以它也不會回滾。

有什麼方法可以確保事件監聽器的操作也被回滾?我剛剛選擇了事務發生得太早的事件嗎?是否有一個事件我應該捕捉髮生回滾的最後一個點後發生的事件,從而確保在發生回滾時不會觸發插入AuditTrail

+1

查看jboss envers,它是用於審計跟蹤的。 – ewernli

回答

5

因爲從來沒有人說,我一直在研究我自己,我的初步解決方案如下:

public class AuditListener implements PostInsertEventListener { 
    private static final long serialVersionUID = -966368101369878522L; 

    @Override 
    public void onPostInsert(PostInsertEvent event) { 
    if (event.getEntity() instanceof Auditable) { 
     Session session = null; 
     try { 
     session = event.getPersister().getFactory().getCurrentSession(); 
     Auditable auditableEntity = (Auditable)event.getEntity(); 
     session.save(new AuditTrail(auditableEntity.getClass().getSimpleName(), 
      auditableEntity.getId(), auditableEntity.getStatus(), 
      auditableEntity.getLastModified())); 
     } catch (HibernateException he) { 
     System.out.println("Horrible error: " + he.getMessage()); 
     session.getTransaction().rollback(); 
     } 
    } 
    } 
} 

注意,我打電話「getCurrentSession()」從PostInsertEventSessionFactoryImplementor。我不確定這是否是一種潛在的危險策略,我也不確定是否有必要保持這種調用,但它似乎起作用,並且其他人從未提供過更好的解決方案。所以你去了。

0

我最近有一個非常類似的問題。這些問題在幾年前被問過,但我認爲這個答案可能有助於其他人。

我遇到的問題是當有是持續可審覈的對象在交易過程中任何形式的例外情況:事務回滾,但我仍然得到一個審計跟蹤記錄插入。

真正的問題在我看來,onPostInsert甚至不應該在事務未提交時被解僱。

原來是冬眠期間的PostInsertEventListener的bug(從2006年到2014年8年!)。 Ref:https://hibernate.atlassian.net/browse/HHH-1582

爲了向後兼容,他們通過引入新的PostCommitInsertEventListener來解決問題。所以我們現在應該使用PostCommitInsertEventListener(對於hibernate> = v4.3。5)和onPostInsert只有在事務成功提交時纔會被觸發