Aku*_*ete 37 grails grails-orm object-persistence
我有一个奇怪的情况,似乎表明GORM缓存问题
//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
Run Code Online (Sandbox Code Playgroud)
我无法理解为什么最后两个查询会返回不同的结果.
但是,如果我对book.save做了以下修改(flush:true).这两个println语句都将返回所有书籍.
我的印象是,在单个应用程序中这不是必需的.
作为参考,我正在使用
@HoàngLong
我的问题如下所示,假设action1/action2被多次调用,没有特定的模式
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
}
Run Code Online (Sandbox Code Playgroud)
一种解决方案是使用一个标志,该标志由action1设置,并在必要时由action2用于刷新.我的问题是,这是一个过于复杂的解决方案,由于数据库调用的复杂性增加,因此无法扩展.
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
}
Run Code Online (Sandbox Code Playgroud)
dsh*_*rew 52
我是否需要在grails中明确刷新GORM保存调用?
简而言之是!,如果你想在你的代码中立即使用该对象.
我遇到了同样的问题,所以这是我读完一些参考后得到的图片.
这是hibernate会话问题.
Hibernate会话在调用控制器操作时创建,在操作返回时结束(或者在错误提前死亡).如果代码没有调用任何事务代码,Hibernate的db交互可以这样描述:
假设条目操作名称是actionName,并且对操作的调用完成而没有任何错误.
注意:中间栏(禁用第二级缓存)因为没有任何交易代码.

如果上面相同的代码有错误:

但是,如果您的操作是调用事务方法或使用withTransaction创建内联事务 (并假设调用操作已完成而没有任何错误).

如果上面的代码有错误:

我希望它有所帮助,但如果我犯了任何错误或错过了包括重点,请评论我,我会更新我的照片.
Hoà*_*ong 32
在您的情况下,第一个语句返回空列表,因为它从数据库中读取数据,但数据尚未存在.
这就是Hibernate的工作原理:当你调用save时(flush: true),它将刷新Hibernate会话,立即将会话中的所有数据持久化到数据库.如果不使用(flush:true),则数据仅记录在Hibernate会话中,并且仅在刷新Hibernate会话时才会持久存储在数据库中.Hibernate会自动确定刷新会话的时间,以优化性能.
通常,您应该让Hibernate为您完成工作(为了优化) - 除非您希望数据立即保留.
根据Peter Ledbrook的说法:
让Hibernate完成它的工作,只需在必要时或至少仅在一批更新结束时手动刷新会话.如果你没有看到数据库中的数据,那么你应该真正使用它.我知道这有点过于愚蠢,但是必须采取这种行动的情况取决于数据库的实施和其他因素.
更新:要清楚在保存所有对象后如何刷新会话一次:
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()
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道你的FlushMode设置是什么.
默认情况下,它设置为" auto ",这意味着会话在每次直接命中DB的查询之前刷新(并且可能在其他情况下也是如此).在这种情况下,您的Foo.findAllByBar应首先刷新会话(可能的性能问题!)并从DB中读取正确的值.
FlushMode还有另外两个值,如果你设置其中一个,那么它就可以解释你的问题.首先是" 手动 ",这意味着您决定手动刷新会话(例如使用save(flush:true)).如果不这样做,那么Foo.findAllByBar会读取过时的DB状态.第二个是" 提交 ",这意味着每次事务提交都会刷新会话.如果你在grails中使用" withTransaction "语句,这非常方便.
资源:http : //schneide.wordpress.com/2011/03/08/the-grails-performance-switch-flush-modecommit/ http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/ HTML/objectstate.html#d0e1215