hibernate Grails中的刷新模式已从AUTO更改为MANUAL

odopli94  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(127)

在将我的Grails项目从1.3.7升级到2.4.0并修复了与新的Grails版本相关的各种问题之后,我意识到对任何对象所做的任何更改都不会再持久化(根本不会),除非调用save(flush:true)
在Grails 1.3.7中,当使用save()保存域示例时,默认行为是自动保存更改,因为hibflushMode =〉FlushMode.AUTO。在Grails 2.4.0中,这不再是真的。任何控制器操作或服务类中的hib会话的默认flushMode是FlushMode.MANUAL
当在BootStrap中检索sessionFactory.currentSession.flushMode时,情况会变得更加奇怪,在BootStrap中它的值为FlushMode.AUTO,在controller action中它的值为FlushMode.MANUAL。这可以通过创建一个新的grails应用程序并将println "flushMode = $sessionFactory.currentSession.flushMode"放入BootStrap和controller action(例如index())中来验证。
我在过去的两天里搜索了各种论坛,没有找到任何合理的解释,为什么在Grails 2.4.0(甚至可能在更早的版本中)中必须改变这一点。我只找到了一些评论,说使用FlushMode.MANUAL有点危险,因为在修改了一些对象后,当查询数据库时,可能会遇到过时的对象。
我知道:

  • 在config中使用grails.gorm.autoFlush = true,可以对每个save()强制执行flush:true
  • 在休眠3和休眠4中,默认刷新模式为FlushMode.AUTO
  • 在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是否是现在所需的默认值?
如果是这样的话:

  • Peter Ledbrook在GRAILS-7180中的评论“...建议不是我们完全禁用自动冲洗模式...”是什么意思
  • 什么是避免遇到陈旧对象问题的 * 最佳实践 *,特别是在对域对象进行复杂操作时,修改、创建新示例和查询都是混合的。

非常感谢-安迪
在阅读了Graemes Answer和他的评论之后,我试图更好地阐明我正在努力解决的问题,并添加了以下简化的域和控制器类来演示该行为:
网域类别消息:

class Msg {

    String  text

    static constraints = {
        text nullable:true
    }
}

和消息控制器:

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>')
    }
}

因此,调用http://localhost/appname/msg/save1的输出为:

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

在这里我不明白,为什么 hibernate 坚持的对象,即使你flushMode是手动的。
调用http://localhost/appname/msg/save2时,输出为:

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

对象不会持久化,因为Hibernate不会发出刷新,因此不会调用sql“update...”命令。
但现在看来,不仅是flushMode是一个问题,而且如果一个人调用hasErrors()或没有!我更困惑了...
如果在Grails 1.3.7中执行此示例,则两个保存操作(save 1和save 2)都将持久保存新创建的msg对象!

sg3maiej

sg3maiej1#

Grails会在验证之前将刷新模式设置为Manual,以防止在验证过程中刷新任何更改(这很常见,因为您可能有一个查询现有数据的自定义验证器)。
如果有任何验证错误,它不会将刷新模式设置回AUTO。这是为了防止保留无效对象。
您可能会发生验证错误,虽然您可以强制刷新,但这是不可取的。

相关问题