如何防止Hibernate在列表中刷新?

时间:2013-01-18 16:42:13

标签: java hibernate

我有一个简单的Hibernate查询,如:

from MyEntity where name = ?

没有什么花哨的,但它在一次相当大的交易中被多次调用(持续一秒钟,可能会加载数十个或数百个实体)。 Profiler显示花费了大量时间:

org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1185)
org.hibernate.internal.SessionImpl.list(SessionImpl.java:1240)
org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)

换句话说 - 在运行实际查询之前刷新更改。

我可以以某种方式阻止Hibernate完成这个冲洗吗?

如果没有,我该怎么做才能让它更快?

2 个答案:

答案 0 :(得分:13)

默认情况下,hibernate会在会话期间发出查询(FlushMode.AUTO)之前刷新,并且会占用大量的CPU时间。如果您的会话中交替运行许多查询和更新,则会特别痛苦。

如果查询可能选择在当前会话期间插入/更新/删除的后退数据,则需要这些刷新。即使您没有修改当前事务中的任何内容,但使用的是事务隔离级别(如read-uncommitted),也可能出现

假设您不想要未提交的读取等,我知道有两种解决方法:

  1. 选择之前您需要的所有内容 进行任何修改(例如,重新订购内容,以便在进行任何修改之前发出所有查询)。
  2. 如果您确定选择了此会话中尚未修改的数据,则可以将flush-mode明确设置为不会触发刷新的内容,如下所示:

    Query query = session.getNamedQuery(SOME_QUERY_NAME);
    query.setFlushMode(FlushMode.COMMIT);
    

答案 1 :(得分:-1)

Hibernate 在 3.3 版本中改变了它的刷新逻辑。

现在它会一直刷新,即使设置为 FlushMode.MANUAL,如果它检测到您正在查询一个有脏实体的表。

我能想到的一些解决方法:

  • 重新排序操作以不查询脏表并设置 FlushMode.COMMIT 或更低。
  • 在修改之前分离实体并稍后重新附加,这样 Hibernate 就不会知道它们已被更改。
  • 提供具有不同行为的自定义 AutoFlushEventListener。这将需要一些低级别的摆弄,并且可能会破坏其他东西。