【问题标题】:Java Hibernate tips about update all table fields performance关于更新所有表字段性能的 Java Hibernate 提示
【发布时间】:2017-06-17 12:40:42
【问题描述】:

我有这样的要求。

protected Integer[] updateFullTable(final Class clazz){
    final ProjectionList projectionList=Projections.projectionList().add(Projections.property("id"),"id");
    final Criteria criteria=session.createCriteria(clazz)
    .add(Restrictions.eq("typeOfOperation",1))
    .add(Restrictions.eq("performUpdate",true));
    criteria.setProjection(projectionList);
    final List idsList=criteria.list();
    final Integer[]ids = transformObjectArrayIntoIntegerArray(idList);
    //NOW WE UPDATE THE ROWS IDS. 
    final Query query=session.createQuery("update "+clazz.getName()+" set activeRegister=true and updateTime=:updateTime where id in (:ids)")
    .setParameter("updateTime",new Date())
    .setParameterList("ids",ids);
    query.executeUpdate();          
    return transform;
}

正如你们所看到的,有时我需要更新表中的所有行,我查询所有行 id,然后在单独的查询中将更新应用于这些 id,但表有时会有很多记录需要介于30 秒到 10 分钟取决于表

我已将此代码更改为只有一个这样的更新。

final Query query=session.createQuery("update "+clazz.getName()+" set activeRegister=true and updateTime=:updateTime where typeOfOperation=1 and performUpdate=true");

通过唯一的查询,我避免了第一个查询,但我不能再返回受影响的 Id。但后来要求是改变一个

final StringBuilder logRevert;

已添加参数。

如果需要,需要存储更新后的 id 以将直接反向更新应用到数据库中。

但是随着我的更新,我无法再获得 ID。我的问题是如何使用存储过程或数据库或休眠中的一些解决方法获取或返回受影响的 id 我的意思是仅通过一个查询或增强代码获得第一个行为..

任何提示。

我试过了

  1. 使用标准
  2. 使用 HQL。
  3. 使用命名查询
  4. 使用 SqlQuery
  5. 不使用转换器返回原始 Object[]

但时代仍然有些高。

我想要类似的东西

query.executeUpdate();   // RETURNS THE COUNT OF THE AFFECTED ROWS

但我需要受影响的 ID……

对不起,如果问题很简单。

更新

使用@dmitry-senkovich,我可以使用 rawSQL 做到这一点,但不能使用 hibernate,这里提出了一个单独的问题。

https://stackoverflow.com/questions/44641851/java-hibernate-org-hibernate-exception-sqlgrammarexception-could-not-extract-re

【问题讨论】:

  • 如果你想最小化资源使用和最大化性能,你必须使用游标或存储过程(它使用游标)如果你不关心浪费一些周期并且你的时钟是可靠的,您还可以更改算法以先进行更新。更新后,您可以在 where 子句中使用为行设置的时间戳获取 id

标签: java mysql hibernate


【解决方案1】:

下面的解决方案呢?

SET @ids = NULL;

UPDATE SOME_TABLE
SET activeRegister = true, updateTime = :updateTime
WHERE typeOfOperation = 1 and performUpdate = true
      AND (SELECT @ids := CONCAT_WS(',', id, @ids));

SELECT @ids;

【讨论】:

  • 我怎样才能使用休眠使用 sqlQuery 左右返回这些 id?
  • @chiperortiz 我看到的最简单的方法是使用本机查询: session.createSQLQuery(this_long_query_above)
  • 但是我得到了ID?我会检查一下。
  • @chiperortiz 您将获得以下格式的字符串“id1, id2, id3, ...”。到目前为止,这是我发现的唯一一个只使用一个电话的东西
  • 我已经尝试过这段代码 session.createSQLQuery(longQuery).uniqueResult() 但抛出异常原因:java.sql.SQLException:无法使用 executeQuery() 发出数据操作语句。跨度>
【解决方案2】:

如果 updateTime 是日期时间 您可以使用 select

选择所有受影响的记录 ID

Date updateTime = new Date(); // time from update

select id from clazz.getName() where updateTime=:updateTime and  activeRegister=true and typeOfOperation=1 and performUpdate=true

【讨论】:

  • 我需要获取 id 并稍后更新这些 id。我只需要使用 1 个 sql 语句或使其尽可能快....
  • @chiperortiz - “尽可能快” - 在你证明它是代码中最慢的部分之前,不要担心优化它。
【解决方案3】:

更新表中的大量行是一项缓慢的操作。这是由于在ROLLBACK 的情况下需要捕获每一行的“旧”值(由于显式ROLLBACKUPDATE 失败、同一事务中的失败或后续查询,或@ 之前的电源故障987654324@ 完成)。

通常的解决方法是重新考虑需要大型UPDATE应用程序设计

另一方面,有一个 可能 对架构的修复。请提供SHOW CREATE TABLE,这样我就不必在下一段中做太多的“挥手”了……

可能最好将需要更新的列移动到单独的并行表中(“垂直分区”)。如果

,这可能是有益的
  • 原始表有很多宽列(TEXTBLOB 等)——无需制作大量副本。
  • 原始表正在同时更新——更新不会相互阻塞。
  • SELECT 访问未更新的列——通过避免某些其他阻塞。

您仍然可以通过JOINing 将两个表放在一起获得原始列集。

【讨论】:

    猜你喜欢
    • 2012-07-28
    • 2016-07-08
    • 1970-01-01
    • 1970-01-01
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    相关资源
    最近更新 更多