berg369
2009-07-27 15:00
采纳率: 63.2%
浏览 195
已采纳

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

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条回答 默认 最新

  • sjynt131 2009-08-06 10:25
    已采纳

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

    点赞 打赏 评论
  • iteye_12540 2009-07-27 15:00

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

    点赞 打赏 评论
  • piggerman 2009-07-27 15:00

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

    点赞 打赏 评论
  • 拼命 狂热自己。。 2009-07-27 15:00

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

    点赞 打赏 评论
  • pepsi2008 2009-07-27 15:00

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

    点赞 打赏 评论
  • iteye_12540 2009-07-27 15:00

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

    点赞 打赏 评论
  • 口袋鸭 2009-07-27 15:00

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

    点赞 打赏 评论
  • sjynt131 2009-07-27 15:00

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

    点赞 打赏 评论
  • piggerman 2009-07-27 15:00

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

    点赞 打赏 评论
  • sjynt131 2009-07-31 13:35

    享元就是经过封装可以被共享的类,做成单例模式是为了保证任何调用者都调用得到同一个对象。比如你的例子简单享元可以这样:
    [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

    点赞 打赏 评论
  • 代码碎片也疯狂 2009-08-01 22:49

    学习了。。。啊哈哈

    点赞 打赏 评论
  • sjynt131 2009-08-04 10:23

    这里的享元只是简单的提供给不同的ACTION去取数据进行操作的。
    比方说你的一个ACTION获得表单提交的数据Bean后可以生成一个Key放到享元中,接下来不管要经过多少个页面,都只需传递这个Key(无论是放到Session还是request中)。这样你最后需要保存这个Bean的Action直接根据Key去享元中取数据即可。
    这样实际上和放到Session差不多的效果,但好处是这个Bean的数据与Session解耦了,只要拿到Key,可以通过其他任意方式对数据进行处理(比如将key放到一个队列,由另一个服务对其进行处理)。

    点赞 打赏 评论

相关推荐 更多相似问题