管理grails应用程序中多个请求的关联

时间:2010-01-21 12:00:21

标签: grails design-patterns associations in-memory

我目前正在实施一个grails web-app,其中包含一些复杂的表单,其中关联图上的修改应该在“内存中”(即http会话)进行管理,只要实体或顶级域名对象未保存。

e.g。

从上到下:文档 - >分类 - >子类别......

要求:只有在保存文档时才能保存对文档/类别/子类别的修改,而不是在其他情况下保存。

我的第一种方法是将关联ID存储在http会话中,但最终会在我的DocumentController.update操作中使用大量线索代码来同步会话状态与当前持久状态

// update some abstract association
for (def Iterator it = documentInstance.association.iterator(); it.hasNext();)  {
  if (!session.association.contains(it.next().someEntity.id))  {
    it.remove()
  }
}

for (def roleTypeId in session.association)  {
  // add/update association
  ... 
}
当涉及到实际修改数据时,线索代码变得更糟类别,意味着在保存顶级实体时必须分离/重新附加/合并修改后的类别对象。

我对你对这种长期工作单元的看法非常感兴趣。

2 个答案:

答案 0 :(得分:2)

您可以使用会话每会话模式a.k.a.“长对话”。试试grails webflow插件,它以这种方式工作,或者如果你认为webflow不适合你的需要,你自己实现会话会话。

基本前提是在对话开始时打开一个新的休眠会话(使用flush mode = manual)并将其存储在用户的http会话中。在每个后续http请求开始时,您需要确保sessionFactory.getCurrentSession返回会话的hibernate会话,并记住在每个请求结束时断开此会话以关闭请求之间的jdbc连接。当您到达会话结束时,您将刷新会话以保留所有更改,或关闭而不刷新以取消它们。

hibernate网站/ Java Persistence with Hibernate一书有一些关于如何做到这一点的非常好的信息,但除了webflow之外,grails中没有开箱即用的支持。我正在编写SessionPerConversation插件,但现在还很早。我的方法是查看grails 1.2.0源代码并复制它们如何实现.withNewSession,然后用.withConversation,.endConversation和.discardConversation的方法装饰我的控制器。当我进一步深入时,我可能会在State Your Bizness

上发布一些代码

到目前为止我遇到过的问题是......

  1. 如果用户永远不会结束他们的对话,那么休眠会话将保持打开状态(尽管不是jdbc连接),直到他们的http会话超时。如果您支持多个会话,那么每个用户可能有多个hiberate会话,对于高使用率的站点,您可能会遇到内存问题

  2. 您必须注意自动会话刷新。当您新建实体时,可能会发生这种情况,具体取决于您使用哪种策略生成ID,或者您的呼叫交易服务

答案 1 :(得分:0)

一些想法:

将代码从控制器中分离出来并将其置于服务中。

将服务的静态“事务”属性设置为false并控制事务。它可能看起来像这样:

class DocumentService {
    // take control from spring
    static transactional = false

    void updateMethod() {
        Document.withTransaction { transact ->
            // handle your business

            // problems? - you can always rollback without breaking anything
            transact.setRollbackOnly()
        }
    }
}

这将允许您使用“def documentService”行将服务注入控制器。您可以处理服务中的所有逻辑并更彻底地测试所有内容。