java - 尽管有flush(),但“分离的实体传递给坚持”
问题描述
我有一段长时间运行的 JPA+Hibernate 代码,它试图在循环中将大量记录插入数据库。
随着时间的推移(可能是因为 EntityManager 缓存建立/脏检查),处理速度变得越来越慢。em.flush()
为了解决这个问题,我决定em.detach(entity)
在每次迭代结束时,因为一旦实体被持久化,我就不需要它的数据进行进一步处理(不幸的是,我不能使用任何一个em.clear()
或批处理,以减少我的更改的外部影响)。
这是我的代码的一些粗略草稿:
for (...) {
...some selects here...
...create new entity object...
em.persist(entity);
em.flush();
em.detach(entity);
}
使用此序列,对于在上一次迭代中分离的实体,我得到了“传递给持久化的分离实体”错误。为什么flush()
之前的分离不能防止错误?此外,如果我用 替换detach()
,clear()
一切都会完美运行。我的印象是clear()
和detach()
行为方式一样吗?
更奇怪的是,我可以使用以下代码在一次迭代中重现该错误。第二次刷新会引发“分离的实体...”错误。那么这是否意味着第一次冲洗是空操作?
em.flush();
em.detach(entity);
em.flush();
解决方案
flush()
将任何更改与数据库同步,例如,如果您修改了对象和调用flush()
,将触发更新。请注意,您通常不必显式调用它,因为刷新通常发生在事务提交时。
如果要减少持久性上下文中的元素数量,则需要调用clear()
. 这将实质上重置实体管理器
推荐阅读
- node.js - 如何理解节点版本依赖问题
- node.js - 如何使 babel/register 影响导入的文件?
- azure-devops - TFS xaml build vs TFS vNext build vs Octopus Deploy 的可维护性
- c# - 制作高大堆物体的最有效方法?
- regex - 如何在 bash 脚本的 grep 正则表达式字符串中使用变量
- android - 在 Flutter 项目上创建 Android 库
- oracle - Oracle DBMS_LOB.WRITEAPPEND 到 Postgres 的转换
- c# - 支持 IComparable 时的比较语法
- angular - Angular Material 主题问题
- jenkins - 在声明性管道的并行阶段重用代理