Java Hibernate提示有关更新所有表字段的性能

时间:2017-06-17 12:40:43

标签: java mysql hibernate

我有这样的要求。

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. 使用namedQuery
  4. 使用SqlQuery
  5. 不使用变换器返回原始对象[]
  6. 但时间仍然有点高。

    我想要像

    这样的东西
    query.executeUpdate();   // RETURNS THE COUNT OF THE AFFECTED ROWS
    

    但我需要受影响的Ids ......

    很抱歉,问题很简单。

    更新

    使用@dmitry-senkovich,我可以使用rawSQL来实现,但不能使用hibernate,这里有一个单独的问题。

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

3 个答案:

答案 0 :(得分:4)

以下解决方案如何?

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;

答案 1 :(得分:1)

如果 updateTime 是datetime 您可以使用选择

选择所有受影响的记录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

答案 2 :(得分:1)

更新表中的大量行是一种缓慢的操作。这是因为需要抓住“老人”。在ROLLBACK的情况下每行的值(由于显式ROLLBACKUPDATE失败,同一事务中的失败或后续查询,或UPDATE完成之前的电源故障)。

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

另一方面,有一个可能的修复架构。请提供SHOW CREATE TABLE,这样我就不必做太多的手挥动'在以下段落中......

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

,这可能
  • 原始表格有很多宽列(TEXTBLOB等) - 不必制作庞大的副本。
  • 原始表格正在同时更新 - 更新不会相互阻塞。
  • SELECT点击未更新的列 - 避免某些其他阻止。

您仍然可以通过JOINing两个表格获得原始列集。