处理大型域对象列表的最佳方法是什么? 例如,我有“用户”和“预订”域,并且对Book对象有权限READ。 当我添加新书时,我想为本书的所有用户设置READ权限。 起初是一个代码:
def users = Users.findAll{ ... }
users.each { addPermission(book, it, READ) }
我正在使用Spring Security Core和ACL插件。 但现在,我认为这不是将10000个用户对象加载到内存的最佳方式。 我将使用来自Criteria的maxResults(???)的SCROLL方法。 所以我的问题是最好的方法是什么?如何确定MaxResults的最佳数量?
答案 0 :(得分:2)
对于这样的事情,我会进行批量更新。 ExecuteUpdate允许您执行此类操作,并且其性能更高。查看此示例并根据您的需要进行自定义。
def updatedRecords = User.executeUpdate("update User set permission = 'READ' where somecriteriaOrNot ")
答案 1 :(得分:1)
Grails的更多方法是使用批处理。试试下面给出的例子: 编辑:改进了答案。现在,使用基于分页的批处理。
def noOfObjectsTobeProcessedAtAtime=1000//Step or pagination size...
List offsetMaxMapList = (0..User.count()-1).step(noOfObjectsTobeProcessedAtAtime).collect{[max:noOfObjectsTobeProcessedAtAtime,offset:it]}
offsetMaxMapList.each{offsetMaxMap->
addPermissionToUserInBatch(params)
}
def addPermissionToUserInBatch(params){
def batch = []
def session
def users = Users.createCriteria().list(params){}
users.eachWithIndex { user, index ->
batch << user
if (batch.size() >= batchSize) {
User.withTransaction {
batch.each {User userObject ->
addPermission(book, userObject, READ)
}
}
batch.clear()
} else if (batch.size() < batchSize && (users.size() - index - 1) == 0) {
User.withTransaction {
batch.each {User userObject ->
addPermission(book, userObject, READ)
}
}
batch.clear()
}
session = sessionFactory.getCurrentSession()
session.clear()
}
}
希望有所帮助!!!
答案 2 :(得分:0)
谢谢大家。我想总结一下。我希望我能成为一个模板。
def dc = new DetachedCriteria(Users).build{
//some conditions of criteria
}
def count = dc.count()
// Optional:
// dc = dc.build{
// projections { property('username') }
// }
def batchSize = 50 // Hibernate Doc recommends 10..50
0.step(count, batchSize){ offset->
dc.list(offset:offset, max:batchSize).each{
// doSmthWithTransaction(it)
}
//clear the first-level cache
//def hiberSession = sessionFactory.getCurrentSession()
//hiberSession.clear()
// or
Users.withSession { session -> session.clear() }
}
P.S。我在这里不使用Transaction,因为我在doSmthWithTransaction方法
上使用它