刷新模式在Grails中从AUTO更改为MANUAL [英] flush mode changed in grails from AUTO to MANUAL

查看:116
本文介绍了刷新模式在Grails中从AUTO更改为MANUAL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将我的Grails项目从1.3.7升级到2.4.0并修复了与新grails版本相关的各种问题后,我意识到没有任何对任何对象所做的更改会继续存在(除此之外),除非 save(flush:true)被调用。

使用Grails 1.3.7时保存域实例时的默认行为 save()是由于hibernate flushMode => FlushMode.AUTO 而自动保存更改。在Grails 2.4.0中,这不再是事实。任何控制器操作或服务类中的hibernate会话的缺省flushMode都是 FlushMode.MANUAL



在BootStrap中检索 sessionFactory.currentSession.flushMode 时感到陌生,它的值为 FlushMode.AUTO ,并在控制器行动,它具有值 FlushMode.MANUAL 。这可以通过创建一个新的Grails应用程序并在BootStrap和控制器操作(例如index())中放入 printlnflushMode = $ sessionFactory.currentSession.flushMode来验证。 。

在过去的2天里,我一直在搜索各种论坛,并且没有找到任何合理的解释,为什么必须在Grails 2.4.0(或甚至可能在早期版本中)。我只发现评论指出它的风险有 FlushMode.MANUAL ,因为在其他人修改后查询数据库时可能会遇到过时的对象。



我知道:


  • 加上 grails.gorm.autoFlush = true 在配置中,你可以在hibernate3和hibernate4中强制执行一次刷新:对每一个save()

  • 默认flushMode是 FlushMode.AUTO
  • code>
  • 无法在Config.groovy或DataSource.groovy中设置flushMode。我尝试了所有这一切,但没有做任何工作:
    hibernate.flush.mode ='auto'
    hibernate.flushMode ='auto'
    hibernate.session.flush .mode ='auto'
    hibernate.session.flushMode ='auto'
    dataSource.hibernate.flush.mode ='auto'
    dataSource.hibernate.flushMode ='auto'
    dataSource.hibernate.session.flush.mode ='auto'
    dataSource.hibernate.session.flushMode ='auto'
    dataSource.flush.mode ='auto'
    dataSource.flushMode = 'auto'
    dataSource.session.flush.mode ='auto'
    dataSource.session.flushMode ='auto'



请问有人可以在这里抛出一点点亮吗?

其实我想知道是否在Grails 2.4.0 FlushMode.MANUAL 现在是所需的默认值?



如果是这样:


  • 评论内容是什么?......建议不是我们完全禁用AUTO自动冲洗模式......Peter Ledbrook n GRAILS-7180​​

  • 什么是 best practice 不会遇到过时对象的问题,特别是在对域对象执行复杂操作时,修改,创建新实例和查询都混合在一起。

>

非常感谢
- Andi






阅读Graemes答案和他的评论,我试图更好地澄清我正在努力,并添加以下简化的域和控制器类,它们表明了这种行为:


域类Msg:

class Msg {

String text

static constraints = {
text null:true
}
}

和msg控制器

  class MsgController {
de f sessionFactory
$ b $ def index = {
def out = [***当flush in controller / index = \
$ sessionFactory.currentSession.flushMode]
Msg.list()。每个{out<< $ it.id:text = $ it.text}
render out.join('< br>')
}

//这个保存会持续新的msg对象,
//即使flushMode = MANUAL
def save1 = {
def out = [***在控制器中的flushMode / save = \
$ sessionFactory .currentSession.flushMode]
def msg = new Msg(text:'hallo')
if(!msg.save()){
out<< msg有错误!+ msg.errors
}
out<< msg $ msg.id text = $ msg.text
render out.join('< br>')
}

//这个保存不会坚持新的msg对象,即使它的有效
//(差异是调用hasErrors()
def save2 = {
def out = [*** flushMode when in controller / save = \
$ sessionFactory.currentSession.flushMode]
def msg = new Msg(text:'hallo')
if(msg.hasErrors()&&!msg.save )){
out<<msg has errors!+ msg.errors
}
out<<msg $ msg.id使用text = $ msg.text创建
render out.join('< br>')
}
}







所以调用 http:// localhost / appname / msg / save1 输出结果为:

*** flushMode in controller / save1 = MANUAL
msg 1用text = hallo创建

这里我不明白,为什么hibernate会保持对象,即使你的flushMode是MANUAL。 / p>

当调用 http:// localhost / appname / msg / save2 时,输出为:

***在控制器中使用flushMode / save2 = MANUAL
使用text创建的msg null = hallo

该对象不会持久化,因为hibernate不会发出刷新,因此从不会调用sqlupdate .. 。命令。



但是现在看来,不仅flushMode是一个问题,而且如果你调用hasErrors()或者不是!如果你在Grails 1.3.7中做了这个例子,保存动作(save1和save2)会保持新创建的msg对象!

在验证之前,Grails会将刷新模式设置为手动,以防止在验证期间刷新任何更改(这可能非常常见,因为它可能非常常见,你可能有一个查询现有数据的自定义验证器)。



请参阅 https://github.com/grails/grails-data-mapping/blob/master /grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java#L60



如果有任何验证错误,它不会将清除模式设置回AUTO。这是为了防止无效对象被持久存在。



你所看到的是你可能发生了验证错误,尽管你可以强制刷新,但这不是明智的。 p>

After upgrading my Grails project from 1.3.7 to 2.4.0 and after fixing various issues related to the new grails version, I realized that none of the changes done to any object would be persisted anymore (at all) except if save(flush:true) is called.

With Grails 1.3.7 the default behavior when saving a domain instance using save() is that changes get persisted automatically, due to hibernate flushMode => FlushMode.AUTO. In Grails 2.4.0 this is not true anymore. The default flushMode of the hibernate session inside any controller action or service class is FlushMode.MANUAL.

Things get even stranger when retrieving sessionFactory.currentSession.flushMode in BootStrap, where it has a value of FlushMode.AUTO and in a controller action where it has the value FlushMode.MANUAL. This can be verified by creating a new grails app and putting println "flushMode = $sessionFactory.currentSession.flushMode" in BootStrap and in a controller action (eg. index()).

I have been searching through all kind of forums for the last 2 days and did not find any reasonable explanation why this had to be changed in Grails 2.4.0 (or maybe even in earlier versions). I only found comments saying its kind of risky to have FlushMode.MANUAL because you may run into stale objects when querying the db after some others have been modified.

I know that:

  • with grails.gorm.autoFlush = true in config you can force a flush:true to every save()
  • in hibernate3 and hibernate4 default flushMode is FlushMode.AUTO
  • its not possible to set flushMode in Config.groovy nor in DataSource.groovy. I tried all of this and nothing did the job: hibernate.flush.mode = 'auto' hibernate.flushMode = 'auto' hibernate.session.flush.mode = 'auto' hibernate.session.flushMode = 'auto' dataSource.hibernate.flush.mode = 'auto' dataSource.hibernate.flushMode = 'auto' dataSource.hibernate.session.flush.mode = 'auto' dataSource.hibernate.session.flushMode = 'auto' dataSource.flush.mode = 'auto' dataSource.flushMode = 'auto' dataSource.session.flush.mode = 'auto' dataSource.session.flushMode = 'auto'

Please can someone throw a little light in this ?

Actually I would like to know if in Grails 2.4.0 FlushMode.MANUAL is now the desired default?

And if so:

  • What is with the comment "… The proposal is not that we disable the AUTO flush mode completely …" by Peter Ledbrook in GRAILS-7180
  • What is the best practice to not run into the problems with stale objects, especially when doing complex manipulations on domain-objects where modifying, creating new instances and querying is all mixed.

Thanks very much - Andi


Upon reading Graemes Answer and his comments, I tried to better clarify what I am struggling with and added the following simplified domain and controller classes which demonstrate that behavior:

Domain class Msg:

class Msg {

    String  text

    static constraints = {
        text nullable:true
    }
}

and the msg Controller:

class MsgController {
    def sessionFactory

    def index = {
        def out = ["*** flushMode when in controller/index = \
                   $sessionFactory.currentSession.flushMode"]
        Msg.list().each { out << "$it.id: text=$it.text" }
        render out.join('<br>')
    }

    // this save does persist the new msg object, 
    // even if flushMode = MANUAL
    def save1 = {
        def out = ["*** flushMode when in controller/save = \
                   $sessionFactory.currentSession.flushMode"]
        def msg = new Msg(text:'hallo')
        if (!msg.save()) {
            out << "msg has errors! " + msg.errors
        }
        out << "msg $msg.id created with text = $msg.text"
        render out.join('<br>')
    }

    // this save does NOT persist the new msg object, even if its valid
    // (difference is calling hasErrors()
    def save2 = {
        def out = ["*** flushMode when in controller/save = \
                   $sessionFactory.currentSession.flushMode"]
        def msg = new Msg(text:'hallo')
        if (msg.hasErrors() && !msg.save()) {
            out << "msg has errors! " + msg.errors
        }
        out << "msg $msg.id created with text = $msg.text"
        render out.join('<br>')
    }
}


So calling http://localhost/appname/msg/save1 the output is:

*** flushMode when in controller/save1 = MANUAL
msg 1 created with text = hallo

Here I don't get it, why hibernate persists the object, even thou flushMode is MANUAL.

And when calling http://localhost/appname/msg/save2 the output is:

*** flushMode when in controller/save2 = MANUAL
msg null created with text = hallo

The object does not get persisted because hibernate does not issue a flush, thus never calls a sql "update ..." command.

But now it seems that not only the flushMode is an issue, but also if one calls hasErrors() or not! I am puzzled even more ...

If you do this example in Grails 1.3.7 both save actions (save1 and save2) do persist the newly created msg object!

解决方案

Grails will set the flush mode to Manual prior to validating to prevent any changes being flushed during validation (this can be quite common as you may have a custom validator that queries existing data).

See https://github.com/grails/grails-data-mapping/blob/master/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java#L60

If there are any validation errors it will not set the flush mode back to AUTO. This is to prevent invalid objects being persisted.

What you are seeing is you probably have validation errors occurring and although you can force a flush it isn't advisable.

这篇关于刷新模式在Grails中从AUTO更改为MANUAL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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