Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在调用clear()之前,Hibernate使用flushMode=AUTO查询速度要慢得多_Hibernate_Jpa - Fatal编程技术网

在调用clear()之前,Hibernate使用flushMode=AUTO查询速度要慢得多

在调用clear()之前,Hibernate使用flushMode=AUTO查询速度要慢得多,hibernate,jpa,Hibernate,Jpa,我有一个长时间运行(但相当简单)的应用程序,它使用Hibernate(通过JPA)。它在运行过程中经历了相当大的减速。我已经能够缩小范围,只需要偶尔调用entityManager.clear()。当Hibernate的实体管理器跟踪100000个实体时,它比仅跟踪少数实体时慢约100倍(见下面的结果)我的问题是:为什么Hibrate在跟踪很多实体时会减速这么多?还有其他办法吗? !!!更新:我已经能够将这个范围缩小到Hibernate的自动刷新代码 特别是org.hibernate.event

我有一个长时间运行(但相当简单)的应用程序,它使用Hibernate(通过JPA)。它在运行过程中经历了相当大的减速。我已经能够缩小范围,只需要偶尔调用
entityManager.clear()
。当Hibernate的实体管理器跟踪100000个实体时,它比仅跟踪少数实体时慢约100倍(见下面的结果)我的问题是:为什么Hibrate在跟踪很多实体时会减速这么多?还有其他办法吗?


!!!更新:我已经能够将这个范围缩小到Hibernate的自动刷新代码

特别是
org.hibernate.event.internal.AbstractFlushingEventListener
Flushenties()
方法(至少在hibernate 4.1.1.Final中)。其中有一个循环,它迭代持久性上下文中的所有实体,围绕刷新每个实体执行一些广泛的检查(即使在我的示例中所有实体都已刷新!)

因此,部分回答我问题的第二部分,可以通过在查询中将flush模式设置为
FlushModeType.COMMIT
来解决性能问题(请参见下面的更新结果)。e、 g

Place-Place=em.createQuery(“from-Place-where-name=:name”,Place.class)
.setParameter(“名称”,名称)

.setFlushMode(FlushModeType.COMMIT)/也许您熟悉
EntityManager
跟踪持久对象(即通过调用
em.createQuery(…).getSingleResult()创建的对象)。它们在所谓的持久上下文或会话(Hibernate术语)中累积,并允许非常整洁的特性。例如,您可以通过调用mutator方法
setName(…)
来修改对象,
EntityManager
将在适当的时候将内存中的此状态更改与数据库同步(将发出更新语句)。这不需要调用显式的
save()
update()
方法。您只需像处理普通Java对象一样处理该对象,
EntityManager
将负责持久性

为什么这样慢(er)?

首先,它确保内存中每个主键只有一个实例。这意味着,如果两次加载同一行,堆中将只创建一个对象(两个结果都是
==
)。这很有意义——想象一下,如果您有同一行的两个副本,
EntityManager
不能保证它可靠地同步Java对象,因为您可以独立地对这两个对象进行更改。如果需要跟踪的对象很多,那么可能还有很多其他低级操作最终会减慢Entitymanager的运行速度。
clear()
方法实际上删除了持久上下文中的对象,使任务更容易(要跟踪的对象更少=操作更快)

你怎样才能避开它?

如果您的
EntityManager
实现是Hibernate,您可以使用它来解决这些性能问题。我想你可以做到:

无状态会话=((会话)entityManager.getDelegate()).getSessionFactory().openStatelessSession()

(注意!代码未测试,取自其他代码)

但我主要好奇的是,为什么Hibernate似乎会对查询进行O(n)甚至O(n^2)查找——似乎它应该能够在引擎盖下使用哈希表或二叉树来保持查询速度。请注意,当它跟踪100000个实体与100个实体时,会出现2个数量级的差异

O(n²)复杂性源于必须处理查询的方式。因为Hibernate在内部尽可能延迟更新和插入(利用机会将类似的更新/插入分组在一起,特别是在设置对象的多个属性时)

因此,在保存数据库中的查询对象之前,Hibernate必须检测所有对象更改并刷新所有更改。这里的问题是hibernate还有一些通知和拦截正在进行。因此,它迭代由持久性上下文管理的每个实体对象。即使对象本身是不可变的,它也可能包含可变对象甚至引用集合

此外,拦截机制允许您访问被认为是脏的任何对象,以允许您自己的代码实现额外的脏度检查或执行额外的计算,如计算总和、平均值、记录额外信息等

但让我们看一下代码:

用于在中准备查询结果的刷新调用:

DefaultFlushEventListener.onFlush(..)
->抽象FlushingeVentListener.flushEverythingToExecution(事件) ->AbstractFlushingEventListener.prepareEntityFlushes(..)

实施使用:

for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
        EntityEntry entry = (EntityEntry) me.getValue();
        Status status = entry.getStatus();
        if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
            cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
        }
    }
正如您所见,将检索并迭代持久性上下文中所有实体的映射

这意味着对于查询的每次调用,您都要迭代所有以前的结果以检查脏对象。甚至更多的cascadeOnFlush创建了一个新对象并做了更多的事情。下面是cascadeOnFlush的代码:

private void cascadeOnFlush(EventSource session, EntityPersister persister, Object object, Object anything)
throws HibernateException {
    session.getPersistenceContext().incrementCascadeLevel();
    try {
        new Cascade( getCascadingAction(), Cascade.BEFORE_FLUSH, session )
        .cascade( persister, object, anything );
    }
    finally {
        session.getPersistenceContext().decrementCascadeLevel();
    }
}
这就是解释。Hibernate只是在每次发出查询时检查由持久性上下文管理的每个对象

因此,对于阅读本文的每个人来说,这里是复杂性计算: 1.查询:0个实体 2.查询:1个实体 3.查询:2个实体 .. 100查询:100个实体 . .. 100k+1查询:100k个条目

所以我们有O(0+1+2…+n)=O(n(n+1)/2)=O(n²)

这就解释了你的观察。为了保持较小的cpu和内存占用,hibernate管理的持久性上下文应尽可能小。让Hibernate管理100或1000个以上