请求结束时,GORM自动刷新而不调用save

时间:2013-10-27 11:20:55

标签: hibernate grails gorm

我准备了简单的控制器操作来测试与数据库的意外提交更改相关的行为:

def testSimple() {
    Product p = Product.findById(1);

    p.name = "test doneee"

    //p.save flush:true

    respond p
}

即使尚未调用save(),更改仍会保留在数据库中。如何避免在不调用save()的情况下保存实体?

2 个答案:

答案 0 :(得分:5)

Grails注册一个OpenSessionInView拦截器,它启动一个Hibernate会话和每个请求的开始,并在请求结束时刷新并关闭它。这主要是为了允许延迟加载的一对多实例和多对一集合按需加载。您所看到的一个副作用是,即使没有save()调用,更改持久性实例也会导致更改被推送到数据库。这是因为更改它会将其标记为脏,并且Hibernate会在刷新期间发现所有脏对象并将更改推送到数据库。

为避免此类更改被保留,请使用http://grails.org/doc/latest/ref/Domain%20Classes/discard.html方法将其从会话中分离。

P.S。不相关,但您应该使用get而不是findById,因为get执行相同的操作,但具有更好的缓存行为。

答案 1 :(得分:1)

这可能会使您的操作顺序成为一场噩梦。 [见这篇SO帖子] [1] Grails GORM auto update issue

它在大型应用程序上下文中对可怕对象使用getPersistentValue()方法。如果链中的某个地方存在数据库调用,即使它完全不相关,您的持久值也会发生变化。

我确实发现将数据库调用标记为只读会阻止自动保存的触发器。 例如,在服务中

import org.springframework.transaction.annotation.Transactional

  class TestService{

   @Transactional(readOnly = true)
   def queryDatabase(){
      //this operation won't trigger auto updates now, yay
   }

  }

但并非所有情况都是只读的,而且在大型环境中,如果其他开发人员没有明确设置只读,那么您的代码可能会被解决。但是,这对你来说是粗鲁的,通过惯例的复杂性