`
wangdei
  • 浏览: 372908 次
社区版块
存档分类
最新评论

状态对象:数据库的替代者

阅读更多

这是一个实战中非常重要但是容易被忽视的概念,说它重要,是因为它比数据库重要;说它容易被忽视也是同样的原因,它经常被数据库概念替代。

  如果你经验和经历中没有状态这个概念,极端地说:可能你的Java系统经验还未积累到一定程度,状态是每个Java程序员深入Java系统后必然碰到的问题。

  本文我想试图表达的是:状态分两种:活动的状态对象和持久化的状态。而数据库中的数据只是状态的一种持久化结果,而Java系统 运行时,我们更多的可能是和一种活动的状态打交道,这种活动的状态存在内存中,而不是持久化到硬盘上,当然,需要时你可以通过数据库/文件持久化到硬盘上。

  但是,如果你以数据库数据替代状态,那么就可能导致数据库的频繁访问,而且 你的系统会变成一个非对象化的、紧耦合、到处是分散数据块的糟糕系统。这样的系统并不比传统的两层结构好到哪里!也不会比Jsp里嵌入Java代码伪三层系统高明到什么地方。

什么是状态?

  只要有对象就可能有状态,任何一个对象活动时,都有自己的状态属性,类的 字段属性极有可能成为状态,我们现在经常使用的Domain model其实就是一种 包含状态的对象,如果你对状态没有深入掌握,就不可能真正掌握对象系统特点,或者是Domain Model的执行情况。

  对于初学者,经常会疑问:我是将数据放在HttpSession中还是Request中,这里 其实已经开始接触状态,一旦你接触状态,你就要开始小心,因为你可能会将内存泄漏的恶魔导引进来。

  内存泄漏的恶魔爆发时刻取决于你状态的生存周期和系统并发访问量。

  状态的生存周期也就是包含这个状态的对象的生命周期,在简单系统中,我们只 需要通过new创建对象,然后它的消亡就会依靠JVM垃圾回收机制回收,但是事情会这么简单吗?

  状态的危险还会发生在多线程环境下,当多个线程对同一个内存中状态写操作时,这时怎么办?如果这个状态持久化在数据库中,我们会依赖数据库提供的强大事务机制防止这种并发死锁,但是如果是在内存中,你就很难办,因此,我们就尽量避免发生这种多线程同时访问一个状态的现象,而Singleton单例模式极容易发生这种现象,因此实践中,单例模式是J2EE开发中需要避免的,相关帖子讨论见:
http://www.jdon.com/jive/article.jsp?forum=91&thread=17578

  我们接触的Web容器或Jsp/Servlet本质就是一个多线程,这也是很多初学者不知道的, 因为多线程编程是复杂或困难的,因此才有jsp/Servlet这样的上层封装,但是我们使用他们
时,实际在进行多线程编程。

  生命周期和多线程并发使得我们简单的面向对象系统变得异常复杂和难以掌握起来。下面我从这个两个角度,给出两种模式思维解决之道。

生命周期(Scope)

  生命周期(Scope)就是指状态的活动周期,状态对象是什么时候被创建;然后什么时候被销毁,很显然,如果状态对象还没有被创建或已经被销毁,你再访问这个状态对象可能失败,而状态的生命周期控制是可能散落在运行程序的各个地方,如果不象状态模式那样进行统一控制,有可能整个系统是危机四伏的。

  状态的生命周期其实就是对象生命周期,更加细化地说:是Domain Model这个对象的生命周期。这在一个以领域模型为驱动的设计概念中不可回避的课题,而领域模型实战的复杂性就复杂在此。

  状态的生命周期在J2EE中目前有三种:Request/Session和Application,Request是每个客户端发出的一次请求,这是J2EE系统中最基本的事件激活单元, 当服务器端推出一个页面到客户端时,意味着这个Request的结束。那么如果我们的状态保存在Request中,意味着在request结束之前,这个请求经历的任何一个环节都可以对这个状态(对象)进行操作。(掌握这个原理,对于你学习Struts和JSF很有帮助)

  如果是Session,则一直和该客户端有关,只要是该客户端发出的每次request的任何环节都可以对这个状态(对象)进行操作。

  如果是Application,则意味着这个状态是当前Web项目的全局状态。

  这三种状态形式都是以将状态保存在内存中形式存在的,是和持久化状态相对的。是一种内存活动状态。

  生命周期的选取当然是越短越好,这样,这个状态对象就可以被自动销毁,从而避免了
大访问量下的内存泄漏,但是在大访问量下,对象频繁创建和销毁是耗费性能的。

  那么,我们可能经常使用HttpSession来保存状态,这时你极有可能造成内存泄漏,我经常在Jdon论坛上看到将很多数据库数据暂时保存在HttpSession中想法,这是相当危险的,因为一旦并发用户很多,相当多的HttpSession包含了状态,而状态中有可能有更多其他引用,因此内存很快会爆满,或者垃圾回收机制频繁启动,造成应用系统运行暂停或缓慢。

  当你将状态放入HttpSession时,难道没有考虑将其手工消除吗?你要知道所有Web容器(Tomcat/Weblogic等)都不会自动替你清除那些你可能不用的状态对象啊。如果每个人只管新增元素,不管重整或管理,这个系统能不变得混乱吗?代码上这种现象我们是通过Refactoring等结构/行为模式来解决,那么在运行时的状态管理呢?

  状态管理模式或者说对象管理模式正是解决这种问题的。

   按照该模式,你必须手工自己管理放在HttpSession的状态,比如你为每个HttpSession
设立一个状态容器最大尺寸,当超过这个尺寸时,你需要将不用的状态从容器去除, 但是如果这个客户端在Session失效期内又来访问这个状态怎么办?那么你可能需要先临时将状态序列化保存到硬盘上,等Session失效期到达后再真正删除。

  是不是觉得很麻烦?
  捷径是有:
  1. 尽量少使用HttpSession保存状态,这对集群环境也是有利的,见该贴讨论:
http://www.jdon.com/jive/article.jsp?forum=121&thread=22282
那么这些状态放在哪里?使用Application的缓存中,

  2. 使用状态管理中间件,目前有几个选择:EJB的有态Bean;NanoContainer之类状态相关的微容器。那么Spring可以吗?目前没有发现有该功能,甚至在Spring容器内无法直接使用Session性质的状态,只能通过线程级别的ThreadLocal来实现(对不起,你又要开始回到远古的汇编线程时代了);而Jdon框架则可以。

  下面我们谈谈Application的状态,在这个范围内,一个对象状态可以被多个用户反复访问,在这个级别,状态类似数据库中数据,因为可以使用数据库来替代这个级别的状态,所以将状态放入缓存这个深层次技术被大多数初学者忽视了,甚至产生了对数据库依赖心理。

缓存中的状态

  虽然我们将状态保存在Application中,但是我们不可避免还是遇到Session同样的状态管理问题,这个问题所幸的是有专门缓存中间件解决了,当然,在一个多服务器集群系统,如果一个客户端在一个服务器中存放了状态,那么能否在另外一个服务器的内存中访问到呢?回答是肯定的,前提是你必须使用分布式缓存系统。

  目前分布式缓存系统是靠EJB服务器完成,当JBoss 5在2006变成完全解耦、可肢解时,
我们就可以使用原本只支持EJB的JBoss分布式缓存系统来支持我们的普通JavaBeans了(POJO)。这其中目前可能会花费一些力气,因为还没有一个统一的POJO构件接口标准,我相信以后
可能会有。

  如果你不想花费力气,而且可能就只是一台服务器,可以通过双核芯片提升性能,那么单态缓存如果实现?很简单,使用一个缓存产品如OsCache等,将其设定保存在 Application中,或者在web.xml中进行一下简单的配置即可。

  但是,这时你可能碰到另外一个问题:状态的唯一标识,如何通过唯一标识从缓存中那么
多对象状态中取出你要的那一个呢?比较琐碎。

  有没有一个框架帮助你省却这些麻烦,当然推荐Jdon Framework,只要将包含状态的类(主要是Domain Model)继承特定的类或接口(接口在1.4版本实现)即可,这个类的对象运行时就会被缓存或从缓存中读取,再也无需你照料缓存了,就这么简单。

  当然,Jdon Framework的底层缓存器是可以被替代,使用你喜欢的缓存产品,因为jdon
Framework是基于Ioc设计,构件之间是完全解耦、可彻底肢解,能够通过配置替代和更换的。
如果你不明白这个道理,需要好好研究一下Ioc模式带给我们革命性的新变化。

  从以上也可以看出:java复杂性还在于我们需要在编码时,却要想象其运行时的情形。而这种翻译联想没有深厚的实践功底,是很难顺利完成的。

状态管理中间件

  自从J2EE开辟中间件时代以来,就有相当多的高级中间件提供与具体应用无关的通用功能,状态管理中间件很早就有之,EJB的有态Session Bean是一个代表。

  一个中间件不但要有良好的松耦合设计,我们暂时称为静态设计;更要有优秀的动态设计,例如状态管理就属于一种动态设计。

  当然,如果你比较谦虚,不但要选择一些静态设计很好的框架或中间件;而且还要依赖一些拥有良好的动态运行管理的中间件。

  EJB无论是EJB1.X/EJB2.X/EJB3.X.在状态管理上要更加优秀,当然EJB3.X又吸收了优秀的静态设计概念,但是因为需要有一个具体服务器实现过程,这个过程中存在一些陷阱,如In-Box问题等。

  Spring无疑是一个静态设计非常优秀框架,它一直在AOP上孜孜不倦,力图探索一条从AOP角度进行动态运行管理干预捷径,相信会有惊人结果,当然,这种细粒度的AOP需要实践检验,当然如果整入JDK 6.0就更好。

  而Jdon Framework则试图在目前两者之间寻求了一个平衡,既有Ioc/AOP优秀的静态设计,虽然在AOP上不及Spring前卫;但提供了切实Session和Cache状态管理;

  如果你不需要EJB的分布式多服务器集群功能;又不是AOP的超级粉丝,无疑使用Jdon Framework之类的框架无疑是简化方便的。

状态设计的难点

  最后,我不得不重申,并不是有了良好的状态管理框架就可以高枕无忧了,状态的设计其实是我们每个项目必须面临的可变课题,如果状态复杂了可以使用状态模式对付,可惜往往状态不够复杂。

  一个对象本身属性和状态是应该耦合在一起,还是进行分离,属性和状态没有明显的泾渭分明的界限,我们举一个例子:

  论坛Forum这个对象,它有一些字段属性,如论坛名称、论坛描述,还有其他一些相关属性:如该论坛的最新发帖;该论坛的发贴量,后两者好像也是论坛字段,但是他们可能经常变化的,应该属于状态,那么状态和Forum这个主体对象是什么关系?是将该论坛的最新发帖和该论坛的发贴量两个字段并入Forum这个Domain Model中,还是应该单独建立一个状态对象?如果进行分离,分离的依据是什么?

  当然,这里分离的依据是因为对象的生存周期不同。对于我们熟悉的课题,我们能够马上分辨出其中的生存周期,如果是不熟悉领域的建模呢?

  所以,大家已经明白:状态设计的难点是:如何粒度细化地创建模型对象;然后分辨出其中动态的状态性质。这是域建模实战中一个难点。

  很多人问我:你提倡的域建模、设计模式和框架是什么意思?为什么说他们是Java开发设计的三件宝呢?或者说三个典型知识点呢?我想通过本篇我已经通过状态这个概念稍微解释了域建模的一些特点。

  当前,MDA中的四色原型模式Archetype将帮助我们更好地分辨出类的属性、状态和行为,这是一场带来以后十年的软件革命,详情请看下面讨论

分享到:
评论

相关推荐

    Java入门:状态对象--数据库的替代者

    ### Java入门:状态对象——数据库的替代者 在探讨Java系统中的状态管理时,我们往往会遇到一个核心问题:如何在不依赖数据库的情况下有效管理和维护应用的状态?这涉及到一种概念,即“状态对象”(State Object)...

    事务和数据库对象事务和数据库对象.docx

    同义词是一种用于替代对象名称的数据库对象,它允许用户通过不同的名称来访问同一数据库对象。同义词可以被视为数据库对象的别名,但与临时别名不同,它们是持久存储在数据库中的。 ##### 分类 Oracle同义词分为两...

    oracle课件:第四章 数据库对象管理.ppt

    同义词是数据库对象的别名,用于提供数据库对象的替代名称,方便不同用户或应用系统访问。创建同义词的命令为`CREATE SYNONYM synonym_name FOR table_or_view_name;`,这使得用户可以通过同义词而非实际对象名来...

    java应用设计实用素材(专业)

    - **状态对象:数据库的替代者.txt** 提到了使用状态对象来管理复杂状态转换,这是处理业务逻辑中状态变化的有效方法,可以减少对数据库的依赖。 通过学习这些素材,Java开发者不仅可以深入理解设计模式和原则,还...

    数据库常见错误及对策

    在学习数据库的过程中,初学者往往会遇到一些常见的问题,这些问题涉及到表单操作、属性和方法的添加、窗口管理以及表单设计等多个方面。以下是一些具体的错误及其解决对策: 1. **从表单返回值**:在模式表单的...

    数据库学习中的触发器

    3. **前后状态对比**:触发器可以比较数据库在操作前后的状态,根据变化采取相应的行动。 4. **多策略应对**:对于同一类型的操作,一个表上可以有多个触发器,每个触发器执行不同的逻辑。 5. **业务规则强制**:...

    asp数据库实现新闻发布系统

    例如,使用`Connection`对象建立数据库连接,`Command`对象执行SQL命令,`Recordset`对象用于检索和操作数据。 4. 动态网页生成:当用户请求ASP页面时,服务器会执行页面中的脚本,根据需要从数据库中获取数据,...

    数据库基础-练习.docx

    事务日志备份能够确保数据库的一致性和完整性,即使在发生故障的情况下也能通过事务日志恢复到最近的状态。 3. **SQL Server的安全性管理**:SQL Server的安全性管理分为四个主要级别:操作系统级、SQL Server级、...

    15春北航数据库原理及应用在线作业试卷二.pdf

    - 数据库是一个结构化的数据集合,它可以包含多个表、视图和其他数据库对象。 5. 数据库与宿主语言交互: - 通常通过全局变量、局部变量、公共数据区或系统缓冲区来传递信息,具体取决于具体的数据库管理系统。 ...

    基于ASP的歪歪网络备忘录源码.zip

    - Session对象:用于存储用户会话期间的信息,保持状态,实现用户跟踪。 - Application对象:用于在整个应用程序生命周期内共享数据,所有用户都可以访问。 - Server对象:提供了对服务器上的各种服务和方法的访问,...

    《Web开发技术》模拟题(A卷答案).pdf

    24. ADO连接对象:在ASP中,建立与数据库的连接确实需要使用ADO的`Connection`对象。 **简答题知识点** 1. VBScript中的子例程与函数区别:子例程(Sub)只执行操作,没有返回值;而函数(Function)执行操作并有...

    oracle数据库备份

    但export备份并不能替代物理备份,后者对介质失效有保护作用,而export更侧重于防止用户或应用错误。 实施冷备份的具体步骤包括关闭数据库,然后备份所有相关文件。在冷备份脚本文件中,可以列出所有需要备份的文件...

    初学者需要掌握的数据库设计词汇对照表.txt(数据库的一些专用词汇都在这,我在网上总结了好久才出来

    以下是对给定文件中提到的关键数据库设计词汇的详细解析,旨在帮助初学者更好地理解这些概念。 ### 1. Access Method 访问方法指的是数据库管理系统(DBMS)用于存储、检索和更新数据的方式。它涉及数据如何被物理地...

    数据库【MSDE】管理工具

    此外,MSDE的更新和支持已经停止,微软推荐使用SQL Server Express作为替代,后者提供了更全面的功能和持续的技术支持。 总的来说,MSDE管理工具是针对小规模应用和开发环境的数据库解决方案,提供了一套基础的...

    面向对象的23种设计模式

    观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,所有依赖于它的对象都会收到通知并自动更新。 20. **状态模式(State Pattern)**: 状态模式允许一个对象在其内部状态改变时改变它的...

    JS写的在线评论,无刷新提交数据,不需要数据库

    本教程将基于JavaScript实现一个无刷新的在线评论系统,对于JavaScript初学者来说,这是一个很好的学习项目。 ### 1. JavaScript基础知识 在开始构建评论系统之前,我们需要对JavaScript的基础知识有深入的理解。...

Global site tag (gtag.js) - Google Analytics