讨论一下,延迟持久化--这种需求能否实现?

web应用中,第一个请求时不保存到数据库,而保存为一个句柄传递并forword或redirect到另一个表单,第二个表单提交并处理时,调用这个句柄保存到数据库。能不能想出办法实现这种需求呢?

详细说一下这种需求的应用场景:一个组件化的web系统,由容器(控制器并提供其它一些服务)和许多组件组成,其中一个操作是:用户填写容器的一个表单,提交后容器根据某域的值 forward到某个组件的一个表单(但不保存到数据库),用户填写组件表单后提交,第二个表单及处理均是组件中的代码实现的,组件保存第二个表单到数据库,同时需要实现第一个表单数据保存到容器数据库。

组件开发者不应了解容器的细节,因此不能把第一个表单保存在第二个表单的隐藏域中提交后处理,组件开发者甚至不需要了解容器需要的数据库表结构,甚至容器和组件可能属于两个不同的库! 到第二个表单也可能是redirect过去,第二个表单也不会得到前一表单的request对象,但可以得到句柄的ID,将附在redirct请求后传递。

我想这种需求很普遍也很有意义,也不一定是保存数据库了,也可以是延迟做其它的处理工作,但我没有想出实现的办法来,各位高手有没有主意?
问题补充
魔力猫咪:不了解seam,请问其实现这种需求的原理是什么?
kjj:“句柄”只是为了理解的方便,我意思是第一次请求时为操作建立了所有的准备但不立即执行,第二个请求时只调用一下就可以执行了,而且,第二个请求的处理者不需要了解那个操作的细节。
魔力猫咪和miroku都提到了session,但这种方式必须让第二个请求的处理者了解存放在session中的数据结构和需处理的细节,由第二个请求的开发者来做实现,但我希望能完全解耦,第二个请求的处理者只需调用,不需要了解细节。也只有这样才能使容器和运行于其中的组件能够分开。

这种需求能实现吗?

问题补充:
非常感谢大家的意见,高手真多啊!

我想用session可以,就是创建一个类的对象实例,把第一个表单的数据设置为该对象的属性,这个类有一个方法会执行保存数据库,把这个对象放在session中,第二个表单保存时取出调用保存方法就行了。是这样吧?

pocketduck :保存完成后从session中删除这个对象,即使不删除也没关系吧,怎么会出现内存泄漏呢?有必要另外做缓存吗?

sjynt131:查了一下享元类,没看明白它怎么解决我的问题呢?

kjj:谢谢!又了解了RIFE框架,还真是,它与我正在做的东西很相似呢。

问题补充:
sjynt131兄给的单态例子似乎不是典型的享元,享元是支持大量细粒度对象,感觉这里没有这个需求,而且对于延迟操作没有什么关系。
延迟操作看来还是要靠session,可以在第一个表单的处理类中加一个execute方法,取第一个表单的值为该类的属性赋值,但不执行execute方法,即准备好数据但不立即持久化,然后把这个对象放在session中然后重定向,而第二个表单的处理中取出这个对象并执行execute方法就可以了。第二个表单的处理者不需要了解细节,只需从session中取出指定对象并执行,然后从session中清除。
问题补充:
谢谢sjynt131兄,明白了,的确可以作为共享对象来存取。但我觉得还是用session好一点,为什么要和session解耦呢?
设计session这种基于会话生命周期的对象恐怕也是为了解决这类问题吧,session会自动消失掉,而这个共享类需要手工维护,而且不容易避免key的重名在很多人用的情况下。

12个回答

如果是你前面的应用场景,那放到Session中和享元效果区别不大,但你后面提过“也可以是延迟做其它的处理工作”,我的理解可能会有其他的应用。
比如:你所说的第二个请求的执行者如果和第一个执行者不是同一个Session。
另如:每天晚上定时运行一个服务去处理这些Bean,进行一定逻辑处理后才把符合条件的数据进行处理。这种情况当前Action只要将key放到一个队列中就可以了,定时运行的服务到队列中取Key,再去享元中去Bean。这种例子就不能放到Sessioin中了,Session并不是共享的,而且也会自动消失掉。
至于“这个共享类需要手工维护”,我认为处理完数据后再从享元中删除数据才比较复合逻辑,当然你也可以把享元做复杂些,比如设置数据的失效时间,将失效的Bean从享元中去除。这个根据需求而定。
另外Key的生成可以使用类似UUId的产生方式,这样完全可以避免重复。
实际上我提出用享元解决问题主要是因为你提到“但我希望能完全解耦……也只有这样才能使容器和运行于其中的组件能够分开”,而享元可以比较彻底的提供一个解藕的解决方案而已。

Seam完美支持这种操作。如果不是用Seam,建议在Session中临时保存提交的数据。

麻烦你解释一下在web中句柄为何物,难道你要超越web实现web的功能!!

典型的“假动作”太多
类似什么“使能应用”的词汇。。。。。。。。。。

最近单位的项目是一个平台 有遇到楼主相似的情况,解决方法是给页面建一个相应的页面对象,用来保存页面中的所有的数据,放在session中,点了保存后统一存数据,每次,请求页面的时候先读出数据放在session中,可以参看IBM MAXIMO软件的解决方法

从我的理解是,你要填一系列单子。
Seam本身支持数据库链接长链接持有,只有到最后定义的完成的时候才提交事务。也就是做到了跨请求事务处理。所以用来处理你这种流程式处理很容易。
如果你不使用Seam,我给出的解决方案是根据Struts和SpringMVC处理。比如可以把Struts设定为Session而不是Request,这样就可以保证数据了。SpringMVC里你可以通过注解设定传入的参数是Session的。
所谓必须让“第二个请求的处理者了解存放在session中的数据结构和需处理的细节”,只是知道传入的是哪个对象而已。

session可以,但是注意释放相应资源,另外可以增加一个额外的缓存,生命周期与该session相同,第一个表单信息放到该缓存中,第二个表单填好后保存时,从缓存中读取,同样注意释放相应资源,这种操作新手极易搞出内存泄露来

很容易的,写个单例的享元类,里面放个MAP,KEY存句柄,value存Bean

楼上正解,如果你需要更优雅的话,有一个框架可能满足你的需求,叫做java延续编程,rife,你搜索一下,就是为了解决这种winzard的问题!!

享元就是经过封装可以被共享的类,做成单例模式是为了保证任何调用者都调用得到同一个对象。比如你的例子简单享元可以这样:
[code="java"]
public class ShareData{
private Map shareMap=new HashMap();
private static ShareData sharedata=new ShareData();
private ShareData(){

}
public static ShareData getInstance(){

return sharedata;
}
public void addShareMap(String key,Object obj){

shareMap.put(key,obj);

}
public Object getObjectByKey(String key) {
return shareMap.get(key);
}
public Object removeObjectByKey(String key) {
return shareMap.remove(key);
}
}
[/code]
在你应用中的任何方法中都可通过getInstance方法得到享元对象,并随时通过它存取你要的实体Bean

共12条数据 1 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问