我目前正在实施一个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
...
}
当涉及到实际修改数据时,线索代码变得更糟类别,意味着在保存顶级实体时必须分离/重新附加/合并修改后的类别对象。
我对你对这种长期工作单元的看法非常感兴趣。
答案 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
上发布一些代码到目前为止我遇到过的问题是......
如果用户永远不会结束他们的对话,那么休眠会话将保持打开状态(尽管不是jdbc连接),直到他们的http会话超时。如果您支持多个会话,那么每个用户可能有多个hiberate会话,对于高使用率的站点,您可能会遇到内存问题
您必须注意自动会话刷新。当您新建实体时,可能会发生这种情况,具体取决于您使用哪种策略生成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”行将服务注入控制器。您可以处理服务中的所有逻辑并更彻底地测试所有内容。