7

我像这样实现了一个休眠事件监听器:

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插入了一条记录。

我试图把这个:

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

进入这个:

Session session = event.getSession();

但是当我尝试使用该会话时,它会导致堆栈跟踪以 message 结尾Session is closed

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

有没有办法确保事件监听器的动作也被回滚?我是否刚刚选择了在交易中过早发生的事件?是否有一些事件发生在可能发生回滚的最后一点之后,从而确保在AuditTrail发生回滚时不会触发插入?

4

2 回答 2

7

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

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()PostInsertEvent's中调用 "" 的SessionFactoryImplementor。我不确定这是否是一个潜在的危险策略,我也不确定将那个rollback()电话保留在那里是否有意义,但它似乎起作用了,而且没有其他人提供过更好的解决方案。所以你去。

于 2013-01-21T16:22:02.123 回答
6

我最近有一个非常相似的问题。这些问题是几年前提出的,但我认为这个答案可能对其他人有所帮助。

当事务期间存在任何类型的异常情况时,我遇到的问题是保留 Auditable 对象:事务回滚,但我仍然插入了 AuditTrail 记录。

在我看来,真正的问题是,在onPostInsert未提交事务时甚至不应该被解雇。

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

为了向后兼容,他们通过引入新的PostCommitInsertEventListener. 所以我们PostCommitInsertEventListener现在应该使用(对于 hibernate >= v4.3.5)并且onPostInsert只有在事务成功提交时才会被触发

于 2017-08-10T18:20:00.487 回答