如何更新而不使用flush:true

时间:2016-01-07 12:56:15

标签: hibernate grails gorm grails-domain-class

我必须更新一条250.000行桌子。只要我用

street.save(flush:true) 

它有效,但速度非常慢(2 hours for 250.000)。如果我省略flush:true子句,它似乎工作得很快,但根本没有更新。

是否需要进行整体提交,在完成250.000次保存以及如何执行后进行刷新?

彼得

2 个答案:

答案 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 */
        }
    }
}

使用updateAll()

还有另一个选项,仅在以下情况下可用:

  1. 您不需要更新关联的属性。
  2. 在此次更新之前,您没有对相同的域实例进行任何其他更新。
  3. 第二个标准是微妙的,可以让你发疯。 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修改每个符合条件的域类实例。