【问题标题】:The best way to update a millions lines in Java Batch在 Java Batch 中更新数百万行的最佳方法
【发布时间】:2021-03-09 14:41:25
【问题描述】:

我在遗留项目中使用 juste main 方法开发了一批:java 7、hibernate 和 Spring 使用 mysql 数据库。

在这批中,我想更新一个包含超过 5000 万行的表中的几行。 当我每天开始批处理时,我必须更新至少 10000 行。

那么,在mysql中不锁定表的情况下更新行的最佳方法是什么?

只需像这样做一个查询:

update table items set is_achive = true where id in (id1,id2,id3....id10000)

或者像这样使用 for 循环:

for(item p : ItemsList){
   update table item  set is_achive = true where id = p.id
} 

【问题讨论】:

  • Hibernate 会为您批量更新,但您可能会遇到其他问题(例如内存使用),最好先尝试哪种方法更容易编写,并在发现问题时解决问题
  • 不要忘记启动事务,如果更新必须是原子的。否则,如果在运行过​​程中出现异常或错误,您可能会得到部分更新。

标签: java mysql spring hibernate


【解决方案1】:

这取决于您如何确定需要更新的行列表。如果您查询数据库以确定列表,最好只使用如下 DML 语句:

UPDATE Item i SET i.achive = true WHERE ...

如果您关心的是锁定,即行被锁定的时间量,您可以通过使用游标来使用批处理,例如数据源的一些 id。

SELECT id FROM ... WHERE id >= :start AND ...
ORDER BY id
OFFSET 100 -- use a batch size that suites your needs
LIMIT 1 -- use a batch size that suites your needs

limit和for更新可以通过查询来实现

Integer end = entityManager.createQuery("SELECT id FROM ... WHERE id >= :start AND ... ORDER BY id")
    .setParameter("start", previousEnd)
    .setFirstResult(100) // batch size
    .setMaxResults(1)
    .getResultList().stream().findFirst().orElse(null);

然后进行这样的查询

UPDATE Item i SET i.achive = true WHERE i.id BETWEEN :start AND :end

或者如果结尾为空,即最后一批使用

UPDATE Item i SET i.achive = true WHERE i.id >= :start

【讨论】:

    【解决方案2】:

    使用 Hibernate Criteria 构建器:

        CriteriaBuilder cb = this.em.getCriteriaBuilder();
    
        // create update
        CriteriaUpdate<Order> update = cb.createCriteriaUpdate(Order.class);
    
        // set the root class
        Root e = update.from(Order.class);
    
        // set update and where clause
        update.set("amount", newAmount);
        update.where(cb.greaterThanOrEqualTo(e.get("amount"), oldAmount));
    
        // perform update
        this.em.createQuery(update).executeUpdate();
    

    https://thorben-janssen.com/criteria-updatedelete-easy-way-to/

    【讨论】:

      【解决方案3】:

      如果像 Chris B 建议的那样,最好尝试访问根目录,但如果这是您无法做到的,那么您也可以考虑利用此处记录的 Spring JDBC 批量更新操作。这些已经存在了一段时间,因此请查找适合您正在使用的版本的文档。

      https://docs.spring.io/spring-framework/docs/3.0.0.M4/reference/html/ch12s04.html

      【讨论】:

        猜你喜欢
        • 2020-05-30
        • 2019-02-15
        • 1970-01-01
        • 2012-01-07
        • 1970-01-01
        • 2020-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多