【问题标题】:efficient way to do bulk updates where values are assigned serially from a list?从列表中连续分配值的批量更新的有效方法?
【发布时间】:2017-04-17 01:47:13
【问题描述】:

假设有一个具有属性 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 或其他有效方法来实现吗?我很感激任何帮助!谢谢!

【问题讨论】:

    标签: grails hql


    【解决方案1】:

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

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

    当然,如果可以使用@Transactional注解就更好了。

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

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

    【讨论】:

      【解决方案2】:

      如果您的 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() 非常棒时,它会有所帮助。

      【讨论】:

        猜你喜欢
        • 2017-12-27
        • 2012-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多