从列表中按顺序分配值的批量更新的有效方法?

时间:2016-12-02 07:56:25

标签: grails hql

假设存在属性为p的域A.

class A{
 Integer p
}

我有一个A列表

def lis = A.list()

然后我有一个数字列表

def num = [4, 1, 22, ......]

在grails中进行批量更新的最有效方法是什么,其中A的每个对象都是从num序列中分配一个数字。

一种方法可能是

for(int i=0; i<lis.size(); i++){
  lis[i].p = num[i]
  lis[i].save(flush: true)
}

但我认为这个解决方案效率不高。可以使用HQL或其他有效方法实现吗?我感谢任何帮助!谢谢!

2 个答案:

答案 0 :(得分:1)

如果您的A和数字列表是需要处理的大量数据(如果lis.size等于10 000),那么您应该这样做:

  A.withNewTransaction { status -> // begin a new hibernate session

    int stepForFlush = 100
    int totalLisSize = A.count()
    def lis

    for(int k=0; k < totalLisSize; k+=stepForFlush) {

      lis = A.list(max: stepForFlush, offset: k) // load only 100 elements in the current hibernate session
      ...

      for(int i=0; i<lis.size(); i++) {
        lis[i].p = num[k+i]
        lis[i].save()
      }
      A.withSession { session ->
        session.flush() // flush changes to database
        session.clear() // clear the hibernate session, the 100 elements are no more attached to the hibernate session
                        // Then they are now eligible to garbage collection
                        // you ensure not maintaining in memory all the elements you are treating
      }
    } // next iteration, k+=100


  } // Transaction is closed then transaction is commited = a commit is executed to database,
    // and then all changes that has been flush previously are committed.

注意:

在此解决方案中,您不会将所有A元素加载到内存中,当您的A.list()。size()非常棒时,它会有所帮助。

答案 1 :(得分:0)

虽然我同意您的解决方案可能效率低下,但这主要是因为您正在为每次保存提供冲动。因此,使用transaction可以提升性能;它会在提交时自动导致刷新:

A.withTransaction { status ->
    ...

    for(int i=0; i<lis.size(); i++) {
        lis[i].p = num[i]
        lis[i].save()
    }
}

当然,如果您可以使用@ Transactional注释,那会更好。

是的,您可以使用HQL,但这里的根本问题是您的数字列表是任意的,因此您需要多个HQL查询;每次更新都有一个。

首先尝试事务处理方法,因为这是最容易设置的方法。