我在Grails中发现了一些奇怪的东西。
我创建了一个像:
的对象User a = new User()
a.setName("test")
a.save()
之后我调用一个方法,例如setActive喜欢:
a.setActive(true)
和不要调用save()但它保存在数据库中。我不知道为什么?!我觉得这很危险。对此有何建议?
非常感谢,
马
答案 0 :(得分:6)
Grails注册了一个“OpenSessionInView”拦截器,它在每个请求开始时打开一个Hibernate会话,并在完成后刷新并关闭它。这主要适用于延迟加载的集合。如果没有打开的会话,在加载实例后它会立即断开连接,因此尝试访问集合会引发异常。通过保持会话处于活动状态,可以解析集合。
默认情况下,Hibernate会在刷新期间自动推送持久化实例中的更改,因此OSIV拦截器会在请求结束时刷新,因此任何“脏”实例(如User实例)都会将其更改推送到数据库。
要解决此问题,如果您只想暂时修改现有实例,则可以使用read()
方法加载现有实例,例如用于在GSP中呈现,但不希望更改自动保留。
这不适用于你的情况,因为你没有得到一个旧实例,你正在创建它。在你的情况下,只需在保存后调用a.discard()
,这将使它与Hibernate会话断开连接,并且当刷新发生时,Hibernate将无法推送任何内容。
答案 1 :(得分:3)
执行服务方法后(在transactional = true的情况下)grails使用domain / persist对象保存所有更改并刷新休眠会话。
控制器操作中Redirect的相同行为
要回滚更改 - 抛出RuntimeException。
答案 2 :(得分:2)
因为Hibernate在关闭会话之前会自动将所有挂起的更新保存到持久对象。这就是Hibernate的工作原理。
如果您通过调用.save()
来指示您希望对象是持久的,则Hibernate会假定您还希望保存对该对象的任何后续更改。如果您不希望保留更新,我不会在调用a.setActive(true)
时看到这一点。