假设存在属性为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或其他有效方法实现吗?我感谢任何帮助!谢谢!
答案 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查询;每次更新都有一个。
首先尝试事务处理方法,因为这是最容易设置的方法。