2016-05-16 50 views
0

如果我在我的Grails命令对象中使用GORM域对象,命令对象会自动提交对域对象的更改,即使我没有调用save()方法。默认情况下,Grails命令对象为什么会提交对域对象的更改?

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

我可以用下面的注释强制我想要的行为,但那感觉就像我在做这个艰难的方式。

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

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

回答

1

这不是特定于命令对象,它是控制器操作的一般特征。默认情况下,开放会话视图模式处于活动状态,其中创建Hibernate会话并在动作运行前将其绑定到线程本地,并在动作完成后刷新并关闭。从数据库中检索到的任何持久实例(显式地由于查询或在数据绑定期间隐式地)将保持连接到打开的会话,并且在会话刷新时被肮脏检查。任何修改后的实例都会将其更改与其他排队操作一起刷新,无论是否带有save()调用。

使整个方法(或类)事务和只读可能是矫枉过正。更直接的方法是将实例检索为只读,例如,使用read()而不是get(),在执行条件查询等时调用readOnly方法,或者通过调用各自的discard()方法来“分离”修改的实例。另一个选项是在动作结束时清除会话,因此没有任何东西可以自动刷新,例如,

AnyDomainClass.withSession { it.clear() } 

注意,在“只读”模式中获取的实例可以有自己坚持的变化,但Hibernate不会自动做这些情况下任何东西,只有当你明确地调用save()发生。

+0

但我所看到的是绑定在命令对象中的对象隐式地在命令对象之后和控制器动作的第一行之前提交,而不是在动作结束之后提交。除非我如上所述注释,否则我似乎在命令对象中获得一个事务,并在该操作中获得另一个事务。 – DAC

+0

你可以创建一个小型测试应用程序来演示这个吗?我想看看,所以如果你可以在Github或其他在线repo上做些工作,甚至可以将代码压缩并通过电子邮件发送给我,我希望能够追踪到这一点。如果这是一个真正的bug,那么报告它会很好。 –

+0

行,找到了!演示应用程序没有相同的行为。事实证明,我们通过在命令对象中注入一个UtilService来帮助验证,从而导致了这个问题。该服务是**没有注释@Transactional(readOnly = true)',所以使用它开始了一个事务并返回到提交该事务的控制器操作。注释UtilService'@Transactional(readOnly = true)'解决了这个问题。 – DAC

相关问题