【问题标题】:IDLE in transaction when using entity manager flush使用实体管理器刷新时事务中的空闲
【发布时间】:2012-09-05 07:38:02
【问题描述】:

我们将 hiberante、c3p0、postgresql 用于持久层。 在运行数据密集型作业(主要是选择/插入)时,其中一位开发人员决定在提交之前使用 entityManager.flush(),就像这样

entityManager.getTransaction().begin()
insert n elements
entityManager.flush()
entityManager.getTransaction().commit()

一段时间后,所有运行数据密集型作业的线程似乎都被阻塞了,我们发现它们正在等待来自池的数据库连接。 池中处于“空闲事务”状态的所有连接。 这种情况每次都可以复制。

删除flush()后情况就消失了。

有人知道为什么会这样吗?

谢谢:D

【问题讨论】:

标签: hibernate jpa transactions


【解决方案1】:

hibernate 有一个智能缓存系统,它简单地收集要执行的 sql 命令列表,然后在提交时执行它们。 Flush 用于继续并部分执行这些命令。看起来这可能会有所帮助,但是当您考虑到 hibernate 在没有刷新的情况下提交之前不会执行任何操作时,那么您将导致数据库不得不在短时间内处理大型事务,而不是一次处理所有事务。

这相当于将单张纸交给您的同事进行切碎,而不是让他一次切碎多张纸。将这一点与数据库可能在事务中间锁定记录的事实相结合,从您第一次调用刷新的那一刻起,数据库将致力于执行命令的任务,直到您提交。如果数据库没有在等待您并且一次拥有所有命令,它可以在完成实际工作所需的时间内完成。

简而言之,hibernate 知道它在做什么。 Flush 会覆盖 hibernate 的正常功能,如果您不小心,实际上会降低性能。如果顺序很重要(例如在插入之前执行删除),您可能应该只使用刷新。

【讨论】:

  • 那么为什么我们刷新时hibernate会在事务中挂起?这不应该是一个错误吗?
  • @ibrabeicker 好吧,如果它挂起,那么它就是一个错误。尽管您应该确定这不仅仅是一项需要时间才能完成的繁重操作,而且它实际上是挂起的。如果是这种情况,可能有一些记录被锁定并阻止您的插入完成。
  • 因此 hibernate 使用基本的 CrudRepository 方法在不到一秒的时间内插入 30 条记录。它对 1000 条记录使用 10 秒。在这种规模下,将 1 亿条记录插入我的一个简单 Oracle 表(它有一个命名索引和一个整数主键)中需要 10 多天。我认为 hibernate 不够聪明,无法开箱即用地执行批处理作业。
猜你喜欢
  • 2012-03-14
  • 2012-11-24
  • 2020-11-07
  • 2015-10-30
  • 1970-01-01
  • 2015-06-14
  • 1970-01-01
  • 2015-02-18
  • 2015-01-18
相关资源
最近更新 更多