Java Spring-Hibernate使用FlushMode提高事务性能
我正在尝试改进asynk事务方法的性能 在这个任务中,我必须从一个表中读取大约7500条记录,对其进行详细说明,并在另一个表中插入/更新相应的行 我在hibernate中使用spring数据jpa 为了获得可滚动的结果,我将Java Spring-Hibernate使用FlushMode提高事务性能,java,spring,hibernate,entitymanager,spring-data-jpa,Java,Spring,Hibernate,Entitymanager,Spring Data Jpa,我正在尝试改进asynk事务方法的性能 在这个任务中,我必须从一个表中读取大约7500条记录,对其进行详细说明,并在另一个表中插入/更新相应的行 我在hibernate中使用spring数据jpa 为了获得可滚动的结果,我将EntityManager注入到我的服务中 下面是如何获得我的ScrollableResult对象: Session session = (Session) em.unwrap(Session.class); ScrollableResults res = s
EntityManager
注入到我的服务中
下面是如何获得我的ScrollableResult
对象:
Session session = (Session) em.unwrap(Session.class);
ScrollableResults res = session.createQuery("from SourceTable s")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
while (res.next()){
.... // em.flush() called every 40 cycles
}
根据结果循环大约需要60秒
这里是瓶颈。如果在我的循环中执行一个简单的查询:
query = em.createQuery("from DestTable d where d.item.id = :id", DestTable.class);
while (res.next()){
query.setParameter("id", myId).getSingleResult();
}
执行时间变慢x10。。大约需要600秒
我试图修改我的会话
或我的EntityManager
的参数:会话.setFlushMode(FlushModeType.COMMIT)代码>
em.setFlushMode(FlushModeType.COMMIT)代码>
它提高了性能并删除了手动刷新()方法。工作在40秒内完成
因此,我的问题是:
- 在
session
或enityManager
上调用setFlushMode
有什么区别
- 为什么
setFlushMode(FlushModeType.COMMIT)代码>以这种方式提高性能,而我不能仅通过手动刷新entityManager来获得相同的性能
问题在于默认刷新模式为FlushModeType.AUTO
。在自动刷新模式下,Hibernate将在每次查询之前刷新(仅查询,不查找操作)。这意味着在上面的示例中,默认情况下,每次调用getSingleResult()
时,Hibernate都会刷新。之所以这样做,是因为您所做的更改可能会影响查询结果,因此Hibernate希望您的查询尽可能准确,并首先刷新
在第一个示例中,您没有看到性能受到影响,因为您只发出一个查询并滚动浏览它。我找到的最好的解决方案是您提到的,就是将刷新模式设置为COMMIT
。在会话上调用setFlushMode
与在EntityManager上调用setFlushMode之间应该没有区别。一个可能的区别是,在会话上使用它只会覆盖当前事务的flush属性,而在EntityManager上设置它时,所有事务的属性都会被设置。可能吗?不,EntityManager和会话都绑定到第一级上下文。它们具有相同的生命周期。如果您能够在SessionFactory或EntityManagerFactory上设置刷新模式,则可能是这样,但据我所知,没有办法做到这一点。hibernate flush的问题是,这会触发actionqueue的生成,然后对其进行处理。刷新时,管理的实体越多,问题就越明显。Hibernate检查每一次!更改的实例。因此,如果您知道您的代码对查询列表没有影响,那么最后一次刷新(提交时)的解决方案可以解决这个问题。另一种选择是在目标查询之前调用entitymanager上的clear,以使刷新循环尽可能小。一个副作用是记忆足迹变小。