2012-08-27 58 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只有在事务成功提交时才会被触发