使用 EntityManager / Hibernate 进行批量更新

Posted

技术标签:

【中文标题】使用 EntityManager / Hibernate 进行批量更新【英文标题】:Bulk update using EntityManager / Hibernate 【发布时间】:2021-07-01 06:53:51 【问题描述】:

我正在使用 Hibernate,并且(作为示例)一个具有 10000 个条目的 Employee 实体。假设其中 1000 人的薪水为 4000,我想将其增加到 5000。我很难找到有效的方法来做到这一点。

通过获取所有员工并更新相关条目在代码中执行此操作似乎无效、缓慢,并且在某些情况下似乎还会导致“批量更新从更新返回意外的行数”错误。

因此,建议here 使用本机查询似乎更好,但随后您需要更新 Hibernate 缓存以查看下一个请求的更改:

Employee e = em.find(Employee.class, <id ???>);
em.flush();
em.detach(e);
em.createNativeQuery("UPDATE employee SET salery = 5000 where salery = 4000") 
    .executeUpdate();

但是,我不明白如何在发出本机更新查询之前分离实体。 em.find 调用的第二个参数似乎是单个实体的 id?但是Emloyees 在整个应用程序中都使用了,所以我应该如何知道要分离哪些?有没有办法分离所有(例如像 em.detachAll(Employee.class))或者我应该在一个循环中迭代所有 1000 个雇员并单独分离它们?

我也愿意接受其他解决我最初问题的解决方案。

【问题讨论】:

【参考方案1】:

通过获取所有员工并更新相关条目在代码中执行此操作似乎无效,缓慢......

正如hibernate documentation中所述:

Hibernate 原生查询语言和 JPQL(Java 持久性查询语言)都支持 bulk UPDATEDELETE

所以,你可以这样写查询:

int updatedEntities = entityManager.createQuery(
    "update Employee e " +
    "set e.salery = :newSalery " +
    "where e.salery = :oldSalery" )
.setParameter("oldSalery", 4000)
.setParameter("newSalery", 5000)
.executeUpdate();

还请注意,正如 JPA 2.0 规范的第 4.10 节中所述,应注意何时执行 UPDATEDELETE 语句:

在执行批量更新或删除操作时应小心,因为它们可能会导致数据库与活动持久性上下文中的实体之间出现不一致。 一般来说,批量更新和删除操作只能在新的持久性上下文中的事务内执行,或者在获取或访问状态可能受此类操作影响的实体之前执行。

【讨论】:

以上是关于使用 EntityManager / Hibernate 进行批量更新的主要内容,如果未能解决你的问题,请参考以下文章

“ java.lang.NoClassDefFoundError:javax / persistence / criteria / Selection”在JavaEE Maven项目中使用Hibern

何时将 EntityManager.find() 与 EntityManager.getReference() 与 JPA 一起使用

EntityManager.flush 有啥作用,为啥需要使用它?

JPA 之 Hibernate EntityManager 使用指南

使用 entityManager.createNativeQuery(query,foo.class)

不使用 Spring 获取 EntityManager