【问题标题】:Hibernate Event Listeners - RollbackHibernate 事件监听器 - 回滚
【发布时间】:2012-08-27 21:28:39
【问题描述】:

我像这样实现了一个 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 的插入?

【问题讨论】:

  • 看看 jboss envers,它用于审计跟踪。

标签: java hibernate event-listener


【解决方案1】:

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

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();
      }
    }
  }
}

请注意,我从PostInsertEventSessionFactoryImplementor 调用“getCurrentSession()”。我不确定这是否是一种潜在的危险策略,我也不确定将rollback() 电话保留在那里是否有意义,但它似乎起作用了,而且没有人提供过更好的解决方案。就这样吧。

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-22
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2014-02-21
      • 2019-01-22
      相关资源
      最近更新 更多