刷新模式在Grails中从AUTO更改为MANUAL

时间:2014-06-19 14:29:26

标签: hibernate grails save flush

将我的Grails项目从1.3.7升级到2.4.0并在修复了与新grails版本相关的各种问题之后,我意识到对任何对象所做的任何更改都不会再存在(根本不存在),除非{ {1}}被调用。

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

在BootStrap中检索FlushMode.MANUAL时,事情变得更加奇怪,它的值为sessionFactory.currentSession.flushMode,在控制器操作中,它的值为FlushMode.AUTO。这可以通过创建一个新的grails应用程序并将FlushMode.MANUAL放在BootStrap和控制器操作(例如index())中来验证。

过去两天我一直在搜索所有类型的论坛,但没有找到任何合理的解释,为什么必须在Grails 2.4.0中更改(或者甚至在早期版本中)。我只发现评论说println "flushMode = $sessionFactory.currentSession.flushMode"存在风险,因为在修改其他数据库后查询数据库时可能会遇到过时的对象。

我知道:

    在配置中使用FlushMode.MANUAL
  • 可以强制刷新:对每个save()
  • 都为true
  • 在hibernate3和hibernate4中,默认flushMode为grails.gorm.autoFlush = true
  • 无法在Config.groovy或DataSource.groovy中设置flushMode。我尝试了所有这些,但没有做任何工作:FlushMode.AUTO

请问有人可以为此提一点点吗?

其实我想知道Grails 2.4.0 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'现在是否是所需的默认值?

如果是这样的话:

  • 评论是什么“......提案不是我们完全禁用了自动冲洗模式...”作者:Peter Ledbrook在GRAILS-7180
  • 最佳实践是什么不能解决陈旧对象的问题,特别是在对域对象进行复杂操作时,修改,创建新实例和查询都是混合的。

非常感谢 - 安迪


在阅读Graemes Answer和他的评论后,我试图更好地阐明我正在努力解决的问题,并添加了以下简化的域和控制器类来证明这种行为:

域类消息:

FlushMode.MANUAL

和msg控制器:

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

在这里我不明白,为什么hibernate会持久化对象,即使flushMode是MANUAL。

当调用*** flushMode when in controller/save1 = MANUAL msg 1 created with text = hallo 时输出为:

http://localhost/appname/msg/save2

该对象不会被持久化,因为hibernate不会发出flush,因此永远不会调用sql“update ...”命令。

但现在似乎不仅flushMode是一个问题,而且如果一个人调用hasErrors()或者不是!我更困惑了......

如果您在Grails 1.3.7中执行此示例,则保存操作(save1和save2)会保留新创建的msg对象!

1 个答案:

答案 0 :(得分:9)

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。这是为了防止无效对象被持久化。

您所看到的是您可能发生了验证错误,虽然您可以强制进行同花,但这并不可取。