【问题标题】:Hibernate Interceptor onFlushDirty called multiple times with same values使用相同的值多次调用休眠拦截器 onFlushDirty
【发布时间】:2014-05-20 20:05:38
【问题描述】:

我的 HibernateInterceptor 出现问题。我扩展了EmptyInterceptor 并覆盖了onFlushDirty 方法。 我使用这种方法手动检查脏值(将以前的值与当前值进行比较)来为更改的实体编写审计日志。 问题是,在某些特定情况下,会在调用postFlush 方法之前多次将同一实体传递给onFlushDirty 方法。以前的值和当前值不会因调用而改变。所以我的审计日志多次写入相同的更改。 如果我的实体的属性发生更改(例如,从 NEWIN_PROGRESS),则此更改将传递两次或多次到 onFlushDirty。 为什么会这样?这是真正奇怪的行为,我认为这不是预期的。

拦截器onFlushDirty的调用是由Hibernate的auto-flush行为引起的。在会话期间执行查询时,它会刷新会话中的所有脏实体。我希望这对脏实体只执行一次,但似乎即使在刷新之后该实体仍被标记为“脏”。然后在会话中再次执行另一个查询 - 再次刷新实体。旧值和当前值与第一次刷新时相同。

我试图用一个测试用例重现这个问题,但我无法设法引发这样的多次刷新。在我必须调试整个 Hibernate 代码之前,我希望你们 Hibernate 专家能帮助我解决这个问题。

干杯,克里斯

【问题讨论】:

    标签: hibernate interceptor


    【解决方案1】:

    经过一番调试,我找到了onFlushDirty多次调用的原因:

    如上所述,我的应用程序中的刷新模式设置为 AUTO。在事务中执行查询之前,Hibernate 决定是否刷新脏实体。不管这个决定的结果是什么:HibernateInterceptor 中的方法onFlushDirty 肯定会为会话中的每个脏实体调用,即使它决定以后不被刷新。

    如果 A 类型的实体在会话中处于脏状态,并且在此会话中执行实体类型 B 的查询,Hibernate 不会刷新脏实体,因为它不会影响查询正在使用的表,因此不需要冲洗。

    如果在会话中执行了多个查询,则可能会为同一个脏实体调用多次 onFlushDirty 方法,但它永远不会真正刷新到数据库中,并且在提交正在运行的事务之前一直保持脏状态。

    看看Hibernate类DefaultAutoFlushEventListener

    public void onAutoFlush(AutoFlushEvent event) throws HibernateException {
    ...
        if ( flushIsReallyNeeded(event, source) ) {
              log.trace("Need to execute flush");
    ...
        }
        else {
          log.trace("Dont need to execute flush");
    ...
        }
    }
    

    【讨论】:

    • 嗨,克里斯,但是您是通过什么方式解决了您的问题的?
    • 嗨,克里斯,但您是通过什么方式解决了审核日志中记录重复的问题?
    • 嗨,Oleksandr,我在线程保存映射中跟踪已经传递的实体,以确保一个实体没有被存储两次。当 Hibernate 调用拦截器的“afterTransactionCompletion”方法时,我继续对收集的实体进行审计日志处理。我希望这会有所帮助......
    • 感谢您提供信息,克里斯。我已经用不同的方法解决了任务 - 使用 Hibernate Listeners 而不是 Interceptor。
    • 使用监听器是更好的解决方案。不知何故,我需要一些我认为在侦听器界面上不可用的信息。所以我使用了拦截器。现在我知道,这些信息也可以在听众处获得,但没有时间为我切换。
    猜你喜欢
    • 2014-09-29
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    相关资源
    最近更新 更多