Hibernate事件监听器 - 回滚

时间:2012-08-27 21:28:40

标签: java hibernate event-listener

我实现了一个像这样的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();
        }
      }
    }
  }
}

它只是在插入任何AuditTrail对象后立即将Auditable对象插入数据库。

我遇到的问题是,在事务期间出现任何异常情况时,Auditable对象仍然存在:事务被回滚,但我仍然会插入AuditTrail条记录。< / p>

我试着转过身来:

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

进入这个:

Session session = event.getSession();

但是当我尝试使用该会话时,会导致堆栈跟踪以消息Session is closed结束。

问题似乎是事件在事务中间触发,在导致回滚的异常情况之前触发,并且由于事件侦听器必须使用自己的会话,因此它也不会被回滚。

是否有某种方法可以确保事件监听器的操作也回滚?我刚刚选择了在交易中过早发生的事件吗?是否有一些我应该捕获的事件发生在可能发生回滚的最后一点之后,从而确保在发生回滚时不会触发AuditTrail的插入?

2 个答案:

答案 0 :(得分:6)

由于没有人回复,我一直在自己研究,我的初步解决方案如下:

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()的{​​{1}}调用“PostInsertEvent”。我不确定这是否是一个潜在危险的策略,我也不确定是否有意义保持SessionFactoryImplementor呼叫,但似乎功能正常,没有其他人提供更好的解决方案。你去吧。

答案 1 :(得分:0)

我最近遇到了一个非常类似的问题。这些问题是几年前提出的,但我认为这个答案可能有助于其他人。

  

我遇到的问题是,在事务期间出现任何异常情况,持续存在Auditable对象:事务被回滚,但我仍然会插入AuditTrail记录。

在我看来,真正的问题是,print(df.loc[df['ID'] == '12']) 在未提交交易时甚至不会被解雇。

原来这是onPostInsert在冬眠中的一个错误(从2006年到2014年8年!)。参考:https://hibernate.atlassian.net/browse/HHH-1582

为了向后兼容,他们通过引入新的PostInsertEventListener来解决问题。所以我们现在应该使用PostCommitInsertEventListener(对于hibernate&gt; = v4.3.5),只有在成功提交事务时才会触发PostCommitInsertEventListener