0

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

例如

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

要求:对文档/类别/子类别的修改仅应在保存文档时保存,不得在其他情况下保存。

我的第一种方法是将关联 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
  ... 
}

当涉及到实际修改数据(例如类别)时,线索代码变得更加糟糕,这意味着在保存顶级实体时必须分离/重新附加/合并修改后的类别对象。

我会对你对如此长跨度的作品单元的想法非常感兴趣。

4

2 回答 2

2

您可以使用会话每会话模式,也就是“长会话”。试试 grails webflow 插件,它以这种方式工作,或者如果您认为 webflow 不适合您的需求,请自行实施 session-per-conversation。

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

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

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

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

  2. 您必须注意自动会话刷新。当您根据用于 id 生成的策略或调用事务性服务来新建实体时,可能会发生这种情况。

于 2010-01-27T09:53:19.673 回答
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”行将服务注入控制器。您可以处理服务中的所有逻辑并更彻底地测试所有内容。

于 2010-01-21T12:24:49.560 回答