9

我发现 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(); 
}

问题:

  1. 这就是批量更新所需的全部内容吗?还有什么我需要补充的吗?我设置hibernate.jdbc.batch_size", "20"
  2. 这里默认开启乐观锁了吗?(虽然我的实体中没有@Version)
  3. 如果不是@Version,我需要做什么才能强制执行乐观锁定?

选项 2:

Select Case使用语法或 with构造一个查询Criteria API

问题:

  1. 批处理仍然在这里发生吗?(在一个大查询中)
  2. 就性能而言,这是否比第一种方法更好?
  3. 这两个选项中推荐的方法是什么?还有其他更好的方法吗?
4

3 回答 3

5

在您的问题标题中,您提到了批量更新和删除,但这次您实际上需要批处理。

当您想要更新/删除所有匹配相同过滤条件的行时,需要批量更新和删除,这些过滤条件可以在 WHERE 子句中表达。

在这里,您需要 JDBC 批量更新。您需要设置以下配置属性:

<property name="hibernate.jdbc.batch_size" value="50"/>

如果你这样做,你可以简单地更新实体,Hibernate 会为你批处理 UPDATE 语句。

选项 1不是很有用,因为它会生成 N 个无法批处理的 UPDATE 语句。

选项 2也不是很有用,因为它会生成一个非常复杂的查询,其执行计划可能比在简单的批处理 UPDATE 语句中执行所有内容更复杂。

所以,这样做:

  1. 使用分页获取实体
  2. 使用 Hibernate 更新它们并让它为您进行批量更新。

如果您有很多这样的实体,请使用查询分页

当使用批量更新时,Hibernate 不会version像常规实体更新那样自动增加用于乐观锁定的列,因此您需要显式增加version实体属性

于 2018-01-11T16:11:36.343 回答
4

您可以更新对象列表而无需遍历所有集合。

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();
于 2018-03-13T18:41:31.743 回答
2

如果您要使用批处理,请参阅休眠文档的这一章

batch_size 比查询优化更多的是内存优化,查询保持不变,但您也可以通过充分利用内存来最小化往返。您需要每 N 次刷新()和清除()取决于 batch_size 的设置。

但仍然。.

1 个语句中的更新比多个语句中的更新快得多,因此如果您:

  • 可以简单地循环并在 SQL 中执行此操作
  • 无需更新到其他实体的级联
  • 更新多个值时,您确实需要更快的性能
  • 并且不需要其他 HQL 优势,例如防止 sql 注入的准备好的语句

然后你可以考虑只创建本地查询而不是 hql。

于 2013-07-26T04:37:31.100 回答