我是否需要在Grails中显式清除GORM保存调用? [英] Do I ever need to explicitly flush GORM save calls in grails?

查看:131
本文介绍了我是否需要在Grails中显式清除GORM保存调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  //以所有book.status的UNREAD开头。

我有一个奇怪的情况,似乎表明GORM缓存问题。
Book.list()。each {book.status = Status.READ; book.save()}

println(Book.findAllByStatus(Status.READ))//将打印一个空列表
println(Book.list()。findAll(it.status = = Status.READ))//将打印所有图书

我无法理解为什么最后两个查询可以返回不同的结果。



但是,如果我对 book.save(flush:true)进行以下修改。这两种println语句都会返回所有书籍。



我的印象是,在单个应用程序中这不是必需的。



仅供参考我使用


  • DB:mysql

  • Groovy:1.7 .10

  • Grails:1.3.7



@HoàngLong



我的问题如下所示,假设action1 / action2被多次调用很多次,没有特别的模式

  def action1 = {
Foo foo = Foo.get(params.id)
// ...修改foo
foo.save() //如果我在这里刷新,如果按照顺序调用action1,效率会很低,

$ b $ def action2 = {
//如果我在这里刷新,那么效率会很低按顺序调用action2
List< Foo> foos = Foo.findAllByBar(params.bar)
// ...用foos做一些事
}

一种解决方案是设置一个标志,该标志由action1设置,并在必要时由action2使用。我的问题是,这是一个过于复杂的解决方案,随着数据库调用的复杂性增加,这种解决方案无法扩展。

 布尔isFlushed = true 

def action1 = {
Foo foo = Foo.get(params.id)
// ...修改foo
foo.save()
isFlushed = false
}

def action2 = {
if(!isFlushed){
// flush hibernate session here
}
列出< Foo> foos = Foo.findAllByBar(params.bar)
// ...用foos做一些事
}


解决方案

在你的情况下,第一个语句返回空列表,因为它从数据库中读取数据,但数据还没有。



这就是Hibernate的工作方式:当您使用(flush:true)调用save时,它将刷新Hibernate会话,持久化会话中的所有数据到数据库立即 。如果不使用(flush:true),数据仅记录在Hibernate会话中,并且只有在刷新Hibernate会话时才保存在数据库 中。刷新会话的时间由Hibernate自动决定,以优化性能。



一般来说,你应该让Hibernate为你工作(为了优化) - 除非你根据Peter Ledbrook的说法:

lockquote

根据Peter Ledbrook的说法:让Hibernate做它的工作,只有当你
必须手动刷新会话时,或者至少只有在一批更新的最后
时才会手动刷新会话。如果您没有在数据库中看到
数据,那么您应该只使用
,而应该是
。我知道这有点贵
wishy-washy,但是当这种行为是必要的情况下
取决于数据库实现

其他因素。


From GORM Gotchas - 第1部分



更新:在所有对象保存后,清楚如何刷新会话一次:

  import org.hibernate。* 

类SomeController {
SessionFactory sessionFactory

def save = {
assert sessionFactory!= null

//循环并保存您的书籍

def hibSession = sessionFactory.getCurrentSession()
assert hibSession!= null
hibSession.flush()
}
}


I have a strange situation which appears to indicate a GORM cacheing problem

//begin with all book.status's as UNREAD
Book.list().each { book.status = Status.READ ; book.save() }

println (Book.findAllByStatus (Status.READ)) //will print an empty list
println (Book.list().findAll (it.status == Status.READ)) // will print all books   

I cannot understand why the last two queries could return different results.

However if I make the following modification of book.save(flush:true). Both of the println statements will return all books.

I was under the impression that this was not necessary within a single application.

For reference I'm using

  • DB: mysql
  • Groovy: 1.7.10
  • Grails: 1.3.7

@Hoàng Long

My problem is demonstrated below, suppose action1/action2 are both called many many times, in no particular pattern

def action1 = {
   Foo foo = Foo.get(params.id)
   //... modify foo 
   foo.save() //if I flush here, it will be inefficient if action1 is called in sequence
}

def action2 = {
   //if I flush here, it will be inefficient if action2 is called in sequence
   List<Foo> foos = Foo.findAllByBar (params.bar)
   //... do something with foos
}

One solution would be to have a flag which is is set by action1 and used by action2 to flush if necessary. My issue is that this is an overly complex solution, which is not scalable as the complexity of DB calls increases.

boolean isFlushed = true

def action1 = {
   Foo foo = Foo.get(params.id)
   //... modify foo 
   foo.save() 
   isFlushed = false
}

def action2 = {
   if (!isFlushed) {
      //flush hibernate session here
   }
   List<Foo> foos = Foo.findAllByBar (params.bar)
   //... do something with foos
}

解决方案

In your case, the first statement return empty list because it reads data from the database, but the data isn't there yet.

It's how Hibernate works: When you call save with (flush: true), it will flush the Hibernate session, persistent all data in session to database immediately. If not using (flush:true), the data is only recorded in Hibernate session and only get persisted in database when Hibernate session is flushed. The time to flush the session is automatically determined by Hibernate to optimize the performance.

Generally, you should let Hibernate do the work for you (for optimization sake) - unless you want the data are persisted right away.

According to Peter Ledbrook:

Let Hibernate do it's job and only manually flush the session when you have to, or at least only at the end of a batch of updates. You should only really use if you're not seeing the data in the database when it should be there. I know that's a bit wishy-washy, but the circumstances when such action is necessary depend on the database implementation and other factors.

From GORM Gotchas - part 1

UPDATE: to be clear about how to flush the session one time after all the object get saved:

import org.hibernate.*

class SomeController {
  SessionFactory sessionFactory

  def save = {
    assert sessionFactory != null

    // loop and save your books here

    def hibSession = sessionFactory.getCurrentSession()
    assert hibSession != null
    hibSession.flush()
  }
}

这篇关于我是否需要在Grails中显式清除GORM保存调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆