我必须更新一条250.000行桌子。只要我用
street.save(flush:true)
它有效,但速度非常慢(2 hours for 250.000
)。如果我省略flush:true
子句,它似乎工作得很快,但根本没有更新。
是否需要进行整体提交,在完成250.000次保存以及如何执行后进行刷新?
彼得
答案 0 :(得分:1)
见this。它应该一路帮助你。以下是与您相关的代码。
List batch =[]
(0..250000).each{
YourDomain domain= new YourDomain(....)
batch.add(domain)
if(batch.size()>1000){
YourDomain.withTransaction{
for(YourDomain domain in batch){
domain.save()
}
}
batch.clear()
}
session = sessionFactory.getCurrentSession()
session.clear()
}
另一个较短的解决方案:您可以不每次刷新记录,但可以在500条记录后说出。由于hibernate涉及的步骤,刷新每个记录基本上需要时间。我们可以通过减少对DB的调用次数来减少这些。
your_record_list.eachWithIndex{ street, i ->
street.doSomeCalc()
street.save flush:0 == i % 500
}
答案 1 :(得分:1)
使用domainInstance.save(flush: true)
强制SQL查询在此刻执行。这并不意味着当时将更改提交给数据库,但它确实执行了一些SQL。
我认为值得尝试的第一次尝试(因为它最简单)是确保调用save()
的方法是@Transactional
。这允许Hibernate使用它的最佳判断,(尽可能地延迟SQL),而不是强制刷新Hibernate会话。
import org.springframework.transaction.annotation.Transactional
class SomeController {
@Transactional
def save() {
def streets = /* Some GORM query */
streets.each {
/* Make updates here */
it.save() /* No flush needed because the method is transactional */
}
}
}
还有另一个选项,仅在以下情况下可用:
第二个标准是微妙的,可以让你发疯。 DetachedCriteria.updateAll(Map)
未查看未提交的更改。例如,如果您手动进行更改......
someInstance.foo = 'bar'
someInstance.save(flush: true)
...然后使用updateAll()
对同一个实例进行操作,updateAll()
将无法了解您之前所做的事情。
因此,如果情况允许,您可以使用updateAll()
:
@Transactional
def save() {
def streets = Street.where { /* a GORM where query */}
streets.updateAll([propertyA: valueA, propertyB: valueB])
}
正如您所知,updateAll()
根据property-name / property-value Map
修改每个符合条件的域类实例。