• (转帖)数据库时代的终结


    数据库时代的终结

    板桥里人 http://www.jdon.com 2005/04/28

      以数据库为核心的软件时代已经过去,数据库时代早已结束,当我看到J2EE征途中那么多人在对象和数据库之间彷徨痛苦ing的时候,我想我该出来喊一声了。

      其实这句话在几年前肯定有人喊过,因为中间件时代的来临,实际意味着数据库时代终结,正所谓一山无二虎:如果你重视数据库,你的J2EE系统就无法完全OO,只有你忽视数据库,你的系统才有可能完全迈向OO,至于数据库性能调优等特定功能都可交由EJB容器或O/R Mapping工具实现。

      很多年前,包括我自己在内的大部分企业程序员都是从数据库开始我们的职业生涯,最早的是dBase/FoxPro,后来有了 SQL系列数据库, Oracle将数据库时代推向了顶峰。

      每当有一个新项目时,第一步就是首先设计出数据表结构(Table Schema),然后开始使用SQL语句实现业务逻辑,这种开发模式一直重复,就是后来加入了DelPhI/VB,他们也只是承担图形显示实现,这种C/S结构带来最大问题是:非常难于维护,修改起来,迁一动百。

      软件的生命在于运动,当它需要发展时,最棒的软件人员如果对他也束手无策,这是谁的悲哀?

      现在更多人开始接受B/S结构,但是他们中很多人还没有真正明白为什么需要B/S结构,B/S代表的多层架构才是真正目的(因此,伪多层的B/S系统遍地皆是)。

      多层架构实际是将以前系统中的显示功能、业务运算功能和数据库功能完全分开,杜绝彼此的耦合与影响,从而实现松耦合和良好的可维护性。

      一. 从设计上说:由于实现层次完全分离,业务运算功能成为一种中间功能(中间层),它不依赖具体的表现层技术(Jsp/Html applet等),也不依赖具体数据库技术(Oracle/SQL Server),业务运算功能运行在J2EE应用服务器中,当我们的业务运算功能不再依赖数据库时,是否意味着数据库已经不是重点?

      二. 当然,多层结构带来了性能问题:客户端访问数据库中的数据时,通常需要经过多个层次,非常耗费性能, 如何尽量减少数据库访问是J2EE应用系统首要解决的问题,使用存储过程并没有解决这个问题,存储过程的执行还是属于后端,并没有缩短客户端请求所要经历的坎坷路途。

      解决性能问题的根本解决之道是使用对象缓存,现在, 64位CPU提供的巨大内存空间为单台缓存计算提供了硬件基础,更重要的是,这种缓存计算是可伸缩的,通过集群的缓存机制(如JBossCache), 通过增加应用服务器的数量,可以提高整个业务逻辑层的缓存计算能力,抛弃过去那种为内存斤斤计较的老思维吧。

      三. 在系统分析之初是否首先需要数据表设计呢?回答是否定的, 以UML为代表面向对象的分析设计方法已经成为强大工具,随着面向模型驱动分析设计(MDA)的普及, 面向数据库分析方法正在逐步被抛弃,拥有深厚传统数据库分析习惯的程序员必须面对和接受这种挑战。

      纵观整个J2EE系统开发过程,数据库已经从过去的中心位置降为一种纯技术实现,数据库只是状态持久化的一种手段(文件是另外一种实现手段);什么是持久化?这是相对于内存缓存状态而言,持久化就是当内存断电情况下能永久保存状态数据,但是如果J2EE应用服务器是7X24小时集群运行;几乎永不当机,是否有持久化的必要呢?

      很显然,数据库已经沦为与操作系统中文件系统同样的层面,以它为中心的时代真的结束了,IBM早期将DB2数据库开源已经强烈向我们昭示这点。

      对于J2EE初学者来说,尽早抛弃过去的两种影响:过程语言编程习惯和以数据库为中心的设计习惯,从全新的面向对象角度(OOA、OOD和OOP、AOP)来设计开发你的J2EE系统,J2EE设计开发三件宝:Model、Patterns和Framework

      以上不只是理论,而是我每天正在做的,如果你也是或赞同请广为传播,唤醒更多彷徨痛苦的初学者。


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

    板桥里人 http://www.jdon.com 2006/1/2(转载请保留)

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

      如果你经验和经历中没有状态这个概念,极端地说:可能你的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将帮助我们更好地分辨出类的属性、状态和行为,这是一场带来以后十年的软件革命,详情请看下面讨论

    相关参考:

    学生课程评分系统的设计讨论

    数据库时代的终结

    用j2ee架构金融平台的问题

    DDD(Domain-Driven Design领域驱动设计)实战

    更多关于evans ddd讨论

  • 相关阅读:
    全网最新iOS面试题-大厂加薪篇
    iOS面试--虎牙最新iOS开发面试题
    iOS面试--字节跳动最新iOS开发面试题
    去面试腾讯iOS开发要达到咋样的水准?
    “iOS开发” 金三银四如何快速技术晋升?
    突破瓶颈,“iOS开发”,跳槽面试必备题(针对年后面试者)
    解决visio对象在word中显示不全的问题
    word中图片自动编号的交叉引用出现被引用的图片
    elasticsearch 一个分布式多用户能力的全文搜索引擎
    Maven仓库安装配置及使用
  • 原文地址:https://www.cnblogs.com/bigmouthz/p/1040180.html
Copyright © 2020-2023  润新知