为什么 Grails 命令对象默认将更改提交给域对象?

Why do Grails command objects commit changes to domain objects by default?

如果我在我的 Grails 命令对象中使用 GORM 域对象,即使我没有调用 save() 方法,命令对象也会自动提交对域对象的更改。

我想绑定到命令对象中的 GORM 对象,但不保存或提交对数据库的更改。如果我的控制器或我的服务抛出异常,我想要事务回滚。

我可以使用以下注释强制执行我想要的行为,但这感觉就像我在做这件事一样困难。

Controller Class = @Transactional(readOnly = true)
Controller action method = @Transactional
Command Object Class = @Transactional(readOnly = true)
Service Class = @Transactional

我是不是做错了什么,Grails 域对象是否应该由命令对象自动提交,除非我添加所有这些注释?

这不是特定于命令对象,它是控制器操作的一般特征。默认情况下,在视图中打开会话模式是活动的,其中在操作运行之前创建 Hibernate 会话并将其绑定到线程本地,并在操作完成后刷新和关闭。从数据库中检索到的任何持久性实例(显式地因为查询,或隐式地在数据绑定期间)将保持附加到打开的会话,并在会话刷新时进行脏检查。任何修改过的实例都将在有或没有 save() 调用的情况下与其他排队的操作一起刷新它们的更改。

使整个方法(或class)成为事务性的和只读的可能有点矫枉过正。一种更直接的方法是将实例检索为只读,例如使用 read() 而不是 get(),在执行条件查询等时调用 readOnly 方法,或者 'detaching' 通过调用每个实例的 discard() 方法来修改实例。另一种选择是在操作结束时清除会话,这样就没有什么可以自动刷新的,例如

AnyDomainClass.withSession { it.clear() }

请注意,在 'read-only' 模式下检索的实例可以保留其更改,但 Hibernate 不会自动为这些实例执行任何操作,它只会在您显式调用 save().[=17 时发生=]