0

是否仅保留域对象实例上的第一个 save() ?

环境:Grails 3.3.5,GORM 6.1.9 我相信,PostgreSQL 9.5,JDK 1.8.0_171,Ubuntu 16.04。

我的应用程序根据来自多个文本文件的输入创建 Recital(域对象)实例。这是一个数据库加载,所以一切都发生在一个控制器调用中,调用一个服务方法。一笔交易。

service 方法解析输入流以寻找演奏会。当它找到一个时,它会尝试使用findBy方法(演奏会编号)。如果有给定编号的 Recital,它会从输入更新它并执行 save()。否则,它会从输入创建一个新实例并执行 save()。failOnError到处都是很好的衡量标准。演奏会不属于任何东西,没有级联问题。

程序逻辑无法判断修改是否是实例的最后一次更新。因此,每次更改后都会有一个 save() 。但这不起作用。看来,您只能 save() 一次。

在数据库中找到的最终结果是只有第一个 save() 被持久化。在调试正在运行的程序时,我可以验证实例是否已在内存中完全更新。

如果这是正确的,文档应该说:save 方法通知持久性上下文应该在其当前状态下保存或更新实例。此后(在同一事务中)的任何和所有修改都将被忽略。除非使用 flush 参数,否则对象不会立即持久化...

PS save() 文档将“flush: true”解释为刷新持久性上下文。这对新手来说几乎没有解释价值。一些“冲洗”同义词是:清洗、擦除、删除、清除、清扫、擦除。数据库人员可能会将其视为 ROLLBACK 而不是 COMMIT。解释当然是 Hibernate 术语。如果 Grails doco 大部分是独立的,那就太好了。(同一文档中的附带问题。)

4

2 回答 2

1

在太多人浪费时间在这之前,这里有一些新的见解。

恰好 Recital 域有一个嵌入式组件。我的应用程序中的更新仅影响嵌入式组件的成员。

我已经验证,对于同一个实例的三个特定更新,成员在内存中正确更新。但是,在三个更新中的每一个之后, recital.isDirty() 都会返回 false,同样的, recital.isDirty('body') 中的body是嵌入的组件。

我的结论是更新嵌入式组件不一定会在实例上设置脏标志。所以它没有被保存。忘记原始问题中提出的理论。似乎有一个 Grails/GORM 错误。

我现在的解决方法是用executeUpdate替换更新。一个kludge,但我在这上面花了太多时间,必须继续。

编辑:不是错误。GORM 现在需要对嵌入的类进行注释,@DirtyCheck以便进行脏检查。结案。

于 2018-07-06T13:09:15.687 回答
0

如果我不在交易中,我只能看到所描述的行为,无论如何这都是不好的做法。所以我怀疑你不是在交易中,或者不是一直在交易中。你确定所有涉及的方法都用@Transactional注释吗?

的意思flush: true不是提交,而是执行对数据库的插入/更新,所以 Tuomas 的建议应该有效,但如果我是对的,你仍然在事务之外,如果发生异常,你有部分保存的数据。仅当您使用 @Transactional 注释所有方法时,才会放置提交,但如果存在未捕获的 RunTimeException,您将获得回滚。

在同一事务中考虑这一点:

Recital.save(); Racital.count()-> 0

Recital.save(flush: true); Racital.count()-> 1

如果查看 SQL 日志,您可以看到仅保存了新对象的第一个 .save(),所有更新都将保留,直到您离开事务,这可能会节省开销。我想,由于您不在事务中,因此最后一次更新将永远不会执行。

顺便说一句,IMO grails 文档是我所知道的最好的 OSS 项目之一。如果您稍后查看它,您可能会看到有关陷阱的提示,但它不会在所有地方重复它们。

于 2018-07-05T19:45:09.497 回答