2017-06-17 45 views
4

我有这样的需求。Java 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"); 

而且与仅查询我避免先查询,但我不能不再返回受影响的标识。但后来要求变更为

final StringBuilder logRevert; 

参数已添加。

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

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

任何提示。

我已经试过

  1. 使用标准
  2. 使用HQL。
  3. 使用namedQuery
  4. 使用SqlQuery类
  5. 不使用变压器回到我原始的对象[]

但仍然多次在某种程度上高。

我想是这样

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

但我需要在受影响的ID ......

很抱歉,如果这个问题很简单。

UPDATE

随着@德米特里 - senkovich我能做到这一点使用rawSQL但不是冬眠分离问题在这里提出。

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

如果要减少资源的使用,最大限度提高性能,你必须使用游标或存储过程(使用光标)如果你不关心浪费了一些周期,你的时钟是可靠的,你也可以改变你的算法首先进行更新。更新后,您可以通过使用时间戳,您为行设置,在我需要获取ID并在以后更新这些ID在哪里条款 –

回答

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; 
+0

我怎样才能返回这些ids使用休眠使用sqlQuery左右? – chiperortiz

+0

@chiperortiz我看到最简单的方法是使用本地查询:执行Session.createSQLQuery(this_long_query_above) –

+0

但我得到的ID?我会看看。 – chiperortiz

1

如果录入为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 
+0

获得ids。我只需要使用1个sql语句或尽可能快...... – chiperortiz

+0

@chiperortiz - “尽可能快” - 不必担心优化,直到您证明它是最慢的部分码。 –

1

更新表中的大量行是一个缓慢的操作。这是由于需要捕捉每行的“老字号”的值在ROLLBACK的情况下(由于明确ROLLBACKUPDATE,故障或在同一交易后续查询,或电源故障的故障前UPDATE结束)。

通常的修复方法是重新考虑应用程序设计,这需要较大的UPDATE

在那里另一方面,有可能修复到架构。请提供SHOW CREATE TABLE所以我没有做尽可能多的“挥手”下段...

可能是更好的移动需要被更新到一个单独的列(S)并行,表格(“垂直分区”)。这可能是有益的,如果

  • 原来的表有大量的列宽(TEXTBLOB等) - 由于不必使大副本。
  • 原始表正被同时更新, - 通过不相互阻塞的更新。
  • SELECT打非更新的列 - 通过避免某些其他的阻塞。

你仍然可以得到原始的一组列 - 通过JOINing这两个表在一起。