JPA - 批量/批量更新 - 更好的方法是啥?
Posted
技术标签:
【中文标题】JPA - 批量/批量更新 - 更好的方法是啥?【英文标题】:JPA - Batch/Bulk Update - What is the better approach?JPA - 批量/批量更新 - 更好的方法是什么? 【发布时间】:2013-07-10 04:08:29 【问题描述】:我发现 JPA 不支持以下更新:
Update Person p set p.name = :name_1 where p.id = :id_1,
p.name = :name_2 where p.id = :id_2,
p.name = :name_3 where p.id = :id_3
....
// It could go on, depending on the size of the input. Could be in 100s
所以我有两个选择:
选项 1:
Query q = em.createQuery("Update Person p set p.name = :name where p.id = :id");
For ( int x=0; PersonsList.length; x++ )
// add name and id parameters
em.executeUpdate();
问题:
-
这就是批量更新所需的全部内容吗?还有什么我需要补充的吗?
我设置
hibernate.jdbc.batch_size", "20"
这里是否默认开启了乐观锁? (虽然我的实体中没有@Version)
如果不是@Version,我需要做什么才能强制执行乐观锁定?
选项 2:
使用Select Case
语法或Criteria API
构造一个查询
问题:
-
批处理是否仍然在这里进行? (在一个大查询中)
就性能而言,这是否比第一种方法更好?
这两个选项中推荐的方法是什么?还有其他更好的方法吗?
【问题讨论】:
来吧,你真的想批量运行 3 行吗? bulk 导致目标表上的 Intent 锁定,效果不好,只需通过em.begin()
开始批处理并调用每个 DML,最后调用 'em.commit();'
没有。它的动态。我刚刚在示例中展示了 3 :-)。可能是 100 秒。
它依赖哥们,你用什么样的数据库?以及您希望多久运行一次此类查询?但如果你问我我更喜欢 DB 更喜欢的方式,并以低优先级并行运行它
我们使用 Oracle。它是一个 Web 服务调用。
好吧,伙计,它会自动设置批量大小,当您将其设置为 20 时,每个批次将有 20 次调用,但不建议用于重负载,通常 batch_size
值为在 10 到 35 之间(受抚养人),对于非常重的负载,使用 db 首选方式 :)
【参考方案1】:
在您的问题标题中,您提到了批量更新和删除,但这次您实际上需要批处理。
Bulk Update and Delete 当您想要更新/删除所有符合相同过滤条件的行时需要Bulk Update and Delete,这些条件可以在 WHERE 子句中表达。
在这里,您需要 JDBC 批量更新。您需要设置以下配置属性:
<property name="hibernate.jdbc.batch_size" value="50"/>
如果您这样做,您可以简单地更新实体,Hibernate 会为您批处理 UPDATE 语句。
选项 1 不是很有用,因为它会生成 N 个无法批处理的 UPDATE 语句。
选项 2 也不是很有用,因为它会生成一个非常复杂的查询,其执行计划可能比在简单的批处理 UPDATE 语句中执行所有内容更复杂。
所以,这样做:
-
使用分页获取实体
使用 Hibernate 更新它们并让它为您进行批量更新。
如果您有很多这样的实体,请使用query pagination。
当使用批量更新时,Hibernate 不会像常规实体更新那样自动增加用于乐观锁定的
version
列,因此您需要 increment theversion
entity attribute explicitly。
【讨论】:
【参考方案2】:您无需遍历所有集合即可更新对象列表。
List<Integer> demo = Arrays.asList(1,2,3,4);
final String update = "UPDATE User u SET u.enabled = true WHERE u.id IN (?1)";
return super.getEntityManager()
.createQuery(update)
.setParameter(1, ids)
.executeUpdate();
【讨论】:
我们如何更新say u.enabled = true 用于少数ID,u.enabled = false 用于其他少数ID? 我认为最好是进行 2 次更新。避免复杂的解决方案。【参考方案3】:如果您要使用批处理,请参阅this chapter of the hibernate documentation
batch_size 比查询优化更多的是内存优化,查询保持不变,但您也可以通过充分利用内存来最小化往返。根据batch_size的设置,你需要每N次flush()和clear()。
但还是。 .
在 1 个语句中更新比在多个语句中更新要快得多,所以如果你:
可以简单地循环并在 SQL 中执行此操作 无需更新到其他实体的级联 更新多个文件时确实需要更快的性能 价值 并且不需要其他 HQL 优势,例如防止 sql 注入的预处理语句那么你可以考虑只创建原生查询而不是 hql。
【讨论】:
但是,如果我使用更新本机查询,我会不会获得“批量更新”模式?有人告诉我使用批量更新。所以我想知道最好的方法是什么 正如我所说,batch_size 只是内存管理的问题,因此您可以在一次提交中提交数万行而不会出现 OutOfMemoryException。因此,如果您的本机查询可以在没有 OutOfMemoryException 的情况下满足您的需求,您可以考虑使用它,但如果不是,您应该使用 HQL。但我认为 SQL 不会有 OutOfMemoryException 问题,因为休眠只是将 persisted 对象保存到会话级缓存。以上是关于JPA - 批量/批量更新 - 更好的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
JPA的批量更新会触发TransactionalEventListener吗?