Grails 3.3:是否只保留第一个 save()?
Grails 3.3: Is only the first save() persisted?
是否只保留域对象实例上的第一个 save()?
环境:Grails 3.3.5,GORM 6.1.9 我相信,PostgreSQL 9.5,JDK 1.8.0_171,Ubuntu 16.04.
我的应用根据大量文本文件的输入创建 Recital(领域对象)实例。这是一个数据库负载,所以一切都发生在一个控制器调用中,调用一个服务方法。一笔交易。
服务方法解析输入流以查找独奏。当它找到一个时,它会尝试 findBy 方法(序言已编号)。如果有给定编号的 Recital,它会根据输入更新它并执行 save()。否则它会根据输入创建一个新实例并执行 save()。 failOnError 无处不在。演奏会不 属于 任何东西,没有级联问题。
程序逻辑无法判断修改是否是实例的最后更新。因此每次更改后都有一个 save() 。但这不起作用。好像只能save()一次。
在数据库中找到的最终结果是只有第一个 save() 被持久化。在调试 运行 程序时,我可以验证实例是否已在内存中完全更新。
如果这是正确的,文档应该说:save 方法通知持久化上下文应该保存或更新实例 在其当前状态。在此之后(在同一事务中)的任何和所有修改都将被忽略。 除非使用 flush 参数,否则不会立即持久化对象...
P.S。 save() 文档将 "flush: true" 解释为 刷新持久性上下文 。这对新手来说没有什么解释价值。一些 "flush" 同义词是:cleanse、erase、expunge、purge、sweep、wipe。数据库人员可能会将其视为 ROLLBACK 而不是 COMMIT。当然,解释是 Hibernate 术语。如果 Grails doco 大部分是独立的,那就太好了。 (同一份文档中的附带问题。)
如果我不在交易中,我只能看到所描述的行为,无论如何这是不好的做法。所以我怀疑你不在交易中,或者不是一直在交易中。
您确定所有涉及的方法都用@Transactional 注释了吗?
flush: true
的意思不是提交,而是对数据库执行insert/update,所以Tuomas的建议应该可以,但如果我是对的,你还是在事务之外,如果发生异常,则您有部分保存的数据。
仅当您将所有方法都用 @Transactional 注释时,才会放置提交,但如果存在未捕获的 RunTimeException,您将获得回滚。
在同一笔交易中考虑这一点:
Recital.save(); Racital.count()
-> 0
Recital.save(flush: true); Racital.count()
-> 1
如果你查看 SQL 日志,你会发现只有新对象的第一个 .save() 被保存,所有更新都被保留直到你离开事务,这可能会节省开销.我猜,因为你不在事务中,所以最后的更新永远不会执行。
顺便说一下,IMO 的 grails 文档是我所知道的最好的 OSS 项目之一。如果您稍后查看它,您可能会看到有关陷阱的提示,但它不会在所有地方重复它们。
在太多人将时间浪费在这上面之前,这里有一些新见解。
碰巧 Recital 域有一个嵌入式组件。我的应用程序中的更新仅影响嵌入式组件的成员。
我已经验证,对于同一个实例的三个特定更新,成员已在内存中正确更新。但是,在三个更新中的每一个 recital.isDirty() returns false 之后,同样 recital.isDirty('body') 其中 body 是嵌入的组件。
我的结论是,更新嵌入式组件不一定会在实例上设置脏标志。所以它没有被保存。忘记原始问题中提出的理论。似乎有一个 Grails/GORM 错误。
我现在的解决方法是用 executeUpdate 替换更新。一个烂摊子,但我在这上面花了太多时间,必须继续。
编辑: 不是错误。 GORM 现在需要使用 @DirtyCheck
注释嵌入式 类 以进行脏检查。案件结案。
是否只保留域对象实例上的第一个 save()?
环境:Grails 3.3.5,GORM 6.1.9 我相信,PostgreSQL 9.5,JDK 1.8.0_171,Ubuntu 16.04.
我的应用根据大量文本文件的输入创建 Recital(领域对象)实例。这是一个数据库负载,所以一切都发生在一个控制器调用中,调用一个服务方法。一笔交易。
服务方法解析输入流以查找独奏。当它找到一个时,它会尝试 findBy 方法(序言已编号)。如果有给定编号的 Recital,它会根据输入更新它并执行 save()。否则它会根据输入创建一个新实例并执行 save()。 failOnError 无处不在。演奏会不 属于 任何东西,没有级联问题。
程序逻辑无法判断修改是否是实例的最后更新。因此每次更改后都有一个 save() 。但这不起作用。好像只能save()一次。
在数据库中找到的最终结果是只有第一个 save() 被持久化。在调试 运行 程序时,我可以验证实例是否已在内存中完全更新。
如果这是正确的,文档应该说:save 方法通知持久化上下文应该保存或更新实例 在其当前状态。在此之后(在同一事务中)的任何和所有修改都将被忽略。 除非使用 flush 参数,否则不会立即持久化对象...
P.S。 save() 文档将 "flush: true" 解释为 刷新持久性上下文 。这对新手来说没有什么解释价值。一些 "flush" 同义词是:cleanse、erase、expunge、purge、sweep、wipe。数据库人员可能会将其视为 ROLLBACK 而不是 COMMIT。当然,解释是 Hibernate 术语。如果 Grails doco 大部分是独立的,那就太好了。 (同一份文档中的附带问题。)
如果我不在交易中,我只能看到所描述的行为,无论如何这是不好的做法。所以我怀疑你不在交易中,或者不是一直在交易中。 您确定所有涉及的方法都用@Transactional 注释了吗?
flush: true
的意思不是提交,而是对数据库执行insert/update,所以Tuomas的建议应该可以,但如果我是对的,你还是在事务之外,如果发生异常,则您有部分保存的数据。
仅当您将所有方法都用 @Transactional 注释时,才会放置提交,但如果存在未捕获的 RunTimeException,您将获得回滚。
在同一笔交易中考虑这一点:
Recital.save(); Racital.count()
-> 0
Recital.save(flush: true); Racital.count()
-> 1
如果你查看 SQL 日志,你会发现只有新对象的第一个 .save() 被保存,所有更新都被保留直到你离开事务,这可能会节省开销.我猜,因为你不在事务中,所以最后的更新永远不会执行。
顺便说一下,IMO 的 grails 文档是我所知道的最好的 OSS 项目之一。如果您稍后查看它,您可能会看到有关陷阱的提示,但它不会在所有地方重复它们。
在太多人将时间浪费在这上面之前,这里有一些新见解。
碰巧 Recital 域有一个嵌入式组件。我的应用程序中的更新仅影响嵌入式组件的成员。
我已经验证,对于同一个实例的三个特定更新,成员已在内存中正确更新。但是,在三个更新中的每一个 recital.isDirty() returns false 之后,同样 recital.isDirty('body') 其中 body 是嵌入的组件。
我的结论是,更新嵌入式组件不一定会在实例上设置脏标志。所以它没有被保存。忘记原始问题中提出的理论。似乎有一个 Grails/GORM 错误。
我现在的解决方法是用 executeUpdate 替换更新。一个烂摊子,但我在这上面花了太多时间,必须继续。
编辑: 不是错误。 GORM 现在需要使用 @DirtyCheck
注释嵌入式 类 以进行脏检查。案件结案。