【问题标题】:Saving new domain objects leads to a immediate flush保存新的域对象会导致立即刷新
【发布时间】:2013-12-11 14:55:15
【问题描述】:

保存新创建的域对象(在控制器中)会导致休眠会话立即刷新。 (我添加了 sleep() 以确保它不是日志记录问题,并且我使用 mysql-query.log 仔细检查了这些调用,而不仅仅是“打印”)

5.times { i ->
        new Foo(bar: "$i").save()
        log.error("$i")
        sleep(1000)
}

启用休眠查询日志会导致

2013-12-11 15:26:41,593 [http-bio-8080-exec-6] DEBUG hibernate.SQL  - insert into foo (version, bar) values (?, ?)
| Error 2013-12-11 15:26:41,596 [http-bio-8080-exec-6] ERROR app.HomeController  - 0
2013-12-11 15:26:42,600 [http-bio-8080-exec-6] DEBUG hibernate.SQL  - insert into foo (version, bar) values (?, ?)
| Error 2013-12-11 15:26:42,605 [http-bio-8080-exec-6] ERROR app.HomeController  - 1
2013-12-11 15:26:43,610 [http-bio-8080-exec-6] DEBUG hibernate.SQL  - insert into foo  (version, bar) values (?, ?)
| Error 2013-12-11 15:26:43,613 [http-bio-8080-exec-6] ERROR app.HomeController  - 2
2013-12-11 15:26:44,618 [http-bio-8080-exec-6] DEBUG hibernate.SQL  - insert into foo (version, bar) values (?, ?)
| Error 2013-12-11 15:26:44,622 [http-bio-8080-exec-6] ERROR app.HomeController  - 3
2013-12-11 15:26:45,626 [http-bio-8080-exec-6] DEBUG hibernate.SQL  - insert into foo (version, bar) values (?, ?)
| Error 2013-12-11 15:26:45,631 [http-bio-8080-exec-6] ERROR app.HomeController  - 4

查看 grails 文档 http://grails.org/doc/latest/ref/Domain%20Classes/save.html

save 方法通知持久性上下文应该保存或更新一个实例。除非使用 flush 参数,否则对象不会立即持久化:

我的问题是:文档是错误的还是这是一个错误?

问题(至少对我而言)是整个会话被刷新,这可能导致不需要的更改被持久化。

我在 grails-2.3.3 和 grails-2.2.4 上复制了这个,并检查了最新的 hibernate3 和 hibernate4 插件。所有配置组合的行为都是相同的,所以我想这是一个误导性文档,但我仍然想仔细检查。

更新

按照 sergio 的要求,这个超级简单的控制器会导致上面的输出。

class HomeController {
 def index(){
  5.times { i ->
   new Foo(bar: "$i").save()
   log.error("$i")
   sleep(1000)
  }
 }  
}

【问题讨论】:

  • 你能分享完整的控制器代码吗?
  • 什么版本的 Grails?
  • 添加了控制器@BurtBeckwith,因为我用 grails-2.3.3 和 grails-2.2.4 以及最新的 hibernate4 和 hibernate3 插件进行了测试。

标签: grails grails-orm


【解决方案1】:

您没有看到刷新,只是 SQL 比您预期的要早。这有点让人毛骨悚然,因为您看到的数据库活动比您预期的要早,但是在请求结束之前没有显式刷新 - 您可以在调试器中看到这一点或启用日志记录。

您看到的是 Hibernate 需要执行插入才能检索自动生成的 id。因此,它为每个save() 调用执行显式插入,但在请求结束时只有一个真正的刷新,由 OpenSessionInView 拦截器触发。

所以文档有点偏离。在新的非持久实例上调用 save() 将触发数据库插入,但不会刷新。在修改后的持久实例上调用 save() 或在持久实例上调用 delete() 不会触发数据库更新,直到显式刷新或 Hibernate 检测到它需要,例如如果您进行查询,因为这可能会受到未刷新数据的影响。

编辑

这里有一个更大的例子来说明发生了什么。首先,我创建 2 个 Foo 并刷新这些保存。然后我编辑并保存一个并删除另一个,两者都没有刷新。我同样创建了 5 个新实例并查看了它们的 SQL,但没有更新或删除的 SQL,因为还没有刷新。最后,当我执行显式刷新时,您确实会看到这两个 SQL 语句:

class HomeController {

   def index() {

      def toEdit = new Foo(bar: 'editme').save()
      def toDelete = new Foo(bar: 'deleteme').save(flush: true)
      println 'created first 2 and flushed'

      toEdit.bar += '_edited'
      toEdit.save()
      toDelete.delete()
      println 'edited one, deleted one'

      5.times { i ->
         new Foo(bar: "$i").save()
         println "created foo $i"
         sleep 1000
      }
      println "created 5"

      println "before explicit flush"
      Foo.withSession { it.flush() }
      println "after explicit flush"
   }  
}

这是输出:

2013-12-11 12:46:20,120 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
2013-12-11 12:46:20,138 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created first 2 and flushed
edited one, deleted one
2013-12-11 12:46:20,188 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created foo 0
2013-12-11 12:46:21,197 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created foo 1
2013-12-11 12:46:22,202 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created foo 2
2013-12-11 12:46:23,211 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created foo 3
2013-12-11 12:46:24,219 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - insert into foo (id, version, bar) values (null, ?, ?)
created foo 4
created 5
before explicit flush
2013-12-11 12:46:25,282 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - update foo set version=?, bar=? where id=? and version=?
2013-12-11 12:46:25,284 [http-bio-9090-exec-1] DEBUG hibernate.SQL  - delete from foo where id=? and version=?
after explicit flush

【讨论】:

  • 嘿伯特!感谢您的回答。我不同意,尽管文档有点偏离。 @peschenbach 从来没有抱怨过会话被刷新到更早,而是对象被保留,尽管文档它们不会。让我们在那里更新文档,不是吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 2013-08-07
  • 2016-04-28
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多