(转帖)数据库时代的终结
數據庫時代的終結
板橋里人 http://www.jdon.com 2005/04/28
以數據庫為核心的軟件時代已經過去,數據庫時代早已結束,當我看到J2EE征途中那么多人在對象和數據庫之間彷徨痛苦ing的時候,我想我該出來喊一聲了。
其實這句話在幾年前肯定有人喊過,因為中間件時代的來臨,實際意味著數據庫時代終結,正所謂一山無二虎:如果你重視數據庫,你的J2EE系統(tǒng)就無法完全OO,只有你忽視數據庫,你的系統(tǒng)才有可能完全邁向OO,至于數據庫性能調優(yōu)等特定功能都可交由EJB容器或O/R Mapping工具實現。
很多年前,包括我自己在內的大部分企業(yè)程序員都是從數據庫開始我們的職業(yè)生涯,最早的是dBase/FoxPro,后來有了 SQL系列數據庫, Oracle將數據庫時代推向了頂峰。
每當有一個新項目時,第一步就是首先設計出數據表結構(Table Schema),然后開始使用SQL語句實現業(yè)務邏輯,這種開發(fā)模式一直重復,就是后來加入了DelPhI/VB,他們也只是承擔圖形顯示實現,這種C/S結構帶來最大問題是:非常難于維護,修改起來,遷一動百。
軟件的生命在于運動,當它需要發(fā)展時,最棒的軟件人員如果對他也束手無策,這是誰的悲哀?
現在更多人開始接受B/S結構,但是他們中很多人還沒有真正明白為什么需要B/S結構,B/S代表的多層架構才是真正目的(因此,偽多層的B/S系統(tǒng)遍地皆是)。
多層架構實際是將以前系統(tǒng)中的顯示功能、業(yè)務運算功能和數據庫功能完全分開,杜絕彼此的耦合與影響,從而實現松耦合和良好的可維護性。
一. 從設計上說:由于實現層次完全分離,業(yè)務運算功能成為一種中間功能(中間層),它不依賴具體的表現層技術(Jsp/Html applet等),也不依賴具體數據庫技術(Oracle/SQL Server),業(yè)務運算功能運行在J2EE應用服務器中,當我們的業(yè)務運算功能不再依賴數據庫時,是否意味著數據庫已經不是重點?
二. 當然,多層結構帶來了性能問題:客戶端訪問數據庫中的數據時,通常需要經過多個層次,非常耗費性能, 如何盡量減少數據庫訪問是J2EE應用系統(tǒng)首要解決的問題,使用存儲過程并沒有解決這個問題,存儲過程的執(zhí)行還是屬于后端,并沒有縮短客戶端請求所要經歷的坎坷路途。
解決性能問題的根本解決之道是使用對象緩存,現在, 64位CPU提供的巨大內存空間為單臺緩存計算提供了硬件基礎,更重要的是,這種緩存計算是可伸縮的,通過集群的緩存機制(如JBossCache), 通過增加應用服務器的數量,可以提高整個業(yè)務邏輯層的緩存計算能力,拋棄過去那種為內存斤斤計較的老思維吧。
三. 在系統(tǒng)分析之初是否首先需要數據表設計呢?回答是否定的, 以UML為代表面向對象的分析設計方法已經成為強大工具,隨著面向模型驅動分析設計(MDA)的普及, 面向數據庫分析方法正在逐步被拋棄,擁有深厚傳統(tǒng)數據庫分析習慣的程序員必須面對和接受這種挑戰(zhàn)。
縱觀整個J2EE系統(tǒng)開發(fā)過程,數據庫已經從過去的中心位置降為一種純技術實現,數據庫只是狀態(tài)持久化的一種手段(文件是另外一種實現手段);什么是持久化?這是相對于內存緩存狀態(tài)而言,持久化就是當內存斷電情況下能永久保存狀態(tài)數據,但是如果J2EE應用服務器是7X24小時集群運行;幾乎永不當機,是否有持久化的必要呢?
很顯然,數據庫已經淪為與操作系統(tǒng)中文件系統(tǒng)同樣的層面,以它為中心的時代真的結束了,IBM早期將DB2數據庫開源已經強烈向我們昭示這點。
對于J2EE初學者來說,盡早拋棄過去的兩種影響:過程語言編程習慣和以數據庫為中心的設計習慣,從全新的面向對象角度(OOA、OOD和OOP、AOP)來設計開發(fā)你的J2EE系統(tǒng),J2EE設計開發(fā)三件寶:Model、Patterns和Framework。
以上不只是理論,而是我每天正在做的,如果你也是或贊同請廣為傳播,喚醒更多彷徨痛苦的初學者。
板橋里人 http://www.jdon.com 2006/1/2(轉載請保留)
這是一個實戰(zhàn)中非常重要但是容易被忽視的概念,說它重要,是因為它比數據庫重要;說它容易被忽視也是同樣的原因,它經常被數據庫概念替代。
如果你經驗和經歷中沒有狀態(tài)這個概念,極端地說:可能你的Java系統(tǒng)經驗還未積累到一定程度,狀態(tài)是每個Java程序員深入Java系統(tǒng)后必然碰到的問題。
本文我想試圖表達的是:狀態(tài)分兩種:活動的狀態(tài)對象和持久化的狀態(tài)。而數據庫中的數據只是狀態(tài)的一種持久化結果,而Java系統(tǒng) 運行時,我們更多的可能是和一種活動的狀態(tài)打交道,這種活動的狀態(tài)存在內存中,而不是持久化到硬盤上,當然,需要時你可以通過數據庫/文件持久化到硬盤上。
但是,如果你以數據庫數據替代狀態(tài),那么就可能導致數據庫的頻繁訪問,而且 你的系統(tǒng)會變成一個非對象化的、緊耦合、到處是分散數據塊的糟糕系統(tǒng)。這樣的系統(tǒng)并不比傳統(tǒng)的兩層結構好到哪里!也不會比Jsp里嵌入Java代碼偽三層系統(tǒng)高明到什么地方。
什么是狀態(tài)?
只要有對象就可能有狀態(tài),任何一個對象活動時,都有自己的狀態(tài)屬性,類的 字段屬性極有可能成為狀態(tài),我們現在經常使用的Domain model其實就是一種 包含狀態(tài)的對象,如果你對狀態(tài)沒有深入掌握,就不可能真正掌握對象系統(tǒng)特點,或者是Domain Model的執(zhí)行情況。
對于初學者,經常會疑問:我是將數據放在HttpSession中還是Request中,這里 其實已經開始接觸狀態(tài),一旦你接觸狀態(tài),你就要開始小心,因為你可能會將內存泄漏的惡魔導引進來。
內存泄漏的惡魔爆發(fā)時刻取決于你狀態(tài)的生存周期和系統(tǒng)并發(fā)訪問量。
狀態(tài)的生存周期也就是包含這個狀態(tài)的對象的生命周期,在簡單系統(tǒng)中,我們只 需要通過new創(chuàng)建對象,然后它的消亡就會依靠JVM垃圾回收機制回收,但是事情會這么簡單嗎?
狀態(tài)的危險還會發(fā)生在多線程環(huán)境下,當多個線程對同一個內存中狀態(tài)寫操作時,這時怎么辦?如果這個狀態(tài)持久化在數據庫中,我們會依賴數據庫提供的強大事務機制防止這種并發(fā)死鎖,但是如果是在內存中,你就很難辦,因此,我們就盡量避免發(fā)生這種多線程同時訪問一個狀態(tài)的現象,而Singleton單例模式極容易發(fā)生這種現象,因此實踐中,單例模式是J2EE開發(fā)中需要避免的,相關帖子討論見:
http://www.jdon.com/jive/article.jsp?forum=91&thread=17578
我們接觸的Web容器或Jsp/Servlet本質就是一個多線程,這也是很多初學者不知道的, 因為多線程編程是復雜或困難的,因此才有jsp/Servlet這樣的上層封裝,但是我們使用他們
時,實際在進行多線程編程。
生命周期和多線程并發(fā)使得我們簡單的面向對象系統(tǒng)變得異常復雜和難以掌握起來。下面我從這個兩個角度,給出兩種模式思維解決之道。
生命周期(Scope)
生命周期(Scope)就是指狀態(tài)的活動周期,狀態(tài)對象是什么時候被創(chuàng)建;然后什么時候被銷毀,很顯然,如果狀態(tài)對象還沒有被創(chuàng)建或已經被銷毀,你再訪問這個狀態(tài)對象可能失敗,而狀態(tài)的生命周期控制是可能散落在運行程序的各個地方,如果不象狀態(tài)模式那樣進行統(tǒng)一控制,有可能整個系統(tǒng)是危機四伏的。
狀態(tài)的生命周期其實就是對象生命周期,更加細化地說:是Domain Model這個對象的生命周期。這在一個以領域模型為驅動的設計概念中不可回避的課題,而領域模型實戰(zhàn)的復雜性就復雜在此。
狀態(tài)的生命周期在J2EE中目前有三種:Request/Session和Application,Request是每個客戶端發(fā)出的一次請求,這是J2EE系統(tǒng)中最基本的事件激活單元, 當服務器端推出一個頁面到客戶端時,意味著這個Request的結束。那么如果我們的狀態(tài)保存在Request中,意味著在request結束之前,這個請求經歷的任何一個環(huán)節(jié)都可以對這個狀態(tài)(對象)進行操作。(掌握這個原理,對于你學習Struts和JSF很有幫助)
如果是Session,則一直和該客戶端有關,只要是該客戶端發(fā)出的每次request的任何環(huán)節(jié)都可以對這個狀態(tài)(對象)進行操作。
如果是Application,則意味著這個狀態(tài)是當前Web項目的全局狀態(tài)。
這三種狀態(tài)形式都是以將狀態(tài)保存在內存中形式存在的,是和持久化狀態(tài)相對的。是一種內存活動狀態(tài)。
生命周期的選取當然是越短越好,這樣,這個狀態(tài)對象就可以被自動銷毀,從而避免了
大訪問量下的內存泄漏,但是在大訪問量下,對象頻繁創(chuàng)建和銷毀是耗費性能的。
那么,我們可能經常使用HttpSession來保存狀態(tài),這時你極有可能造成內存泄漏,我經常在Jdon論壇上看到將很多數據庫數據暫時保存在HttpSession中想法,這是相當危險的,因為一旦并發(fā)用戶很多,相當多的HttpSession包含了狀態(tài),而狀態(tài)中有可能有更多其他引用,因此內存很快會爆滿,或者垃圾回收機制頻繁啟動,造成應用系統(tǒng)運行暫停或緩慢。
當你將狀態(tài)放入HttpSession時,難道沒有考慮將其手工消除嗎?你要知道所有Web容器(Tomcat/Weblogic等)都不會自動替你清除那些你可能不用的狀態(tài)對象啊。如果每個人只管新增元素,不管重整或管理,這個系統(tǒng)能不變得混亂嗎?代碼上這種現象我們是通過Refactoring等結構/行為模式來解決,那么在運行時的狀態(tài)管理呢?
狀態(tài)管理模式或者說對象管理模式正是解決這種問題的。
按照該模式,你必須手工自己管理放在HttpSession的狀態(tài),比如你為每個HttpSession
設立一個狀態(tài)容器最大尺寸,當超過這個尺寸時,你需要將不用的狀態(tài)從容器去除, 但是如果這個客戶端在Session失效期內又來訪問這個狀態(tài)怎么辦?那么你可能需要先臨時將狀態(tài)序列化保存到硬盤上,等Session失效期到達后再真正刪除。
是不是覺得很麻煩?
捷徑是有:
1. 盡量少使用HttpSession保存狀態(tài),這對集群環(huán)境也是有利的,見該貼討論:
http://www.jdon.com/jive/article.jsp?forum=121&thread=22282
那么這些狀態(tài)放在哪里?使用Application的緩存中,
2. 使用狀態(tài)管理中間件,目前有幾個選擇:EJB的有態(tài)Bean;NanoContainer之類狀態(tài)相關的微容器。那么Spring可以嗎?目前沒有發(fā)現有該功能,甚至在Spring容器內無法直接使用Session性質的狀態(tài),只能通過線程級別的ThreadLocal來實現(對不起,你又要開始回到遠古的匯編線程時代了);而Jdon框架則可以。
下面我們談談Application的狀態(tài),在這個范圍內,一個對象狀態(tài)可以被多個用戶反復訪問,在這個級別,狀態(tài)類似數據庫中數據,因為可以使用數據庫來替代這個級別的狀態(tài),所以將狀態(tài)放入緩存這個深層次技術被大多數初學者忽視了,甚至產生了對數據庫依賴心理。
緩存中的狀態(tài)
雖然我們將狀態(tài)保存在Application中,但是我們不可避免還是遇到Session同樣的狀態(tài)管理問題,這個問題所幸的是有專門緩存中間件解決了,當然,在一個多服務器集群系統(tǒng),如果一個客戶端在一個服務器中存放了狀態(tài),那么能否在另外一個服務器的內存中訪問到呢?回答是肯定的,前提是你必須使用分布式緩存系統(tǒng)。
目前分布式緩存系統(tǒng)是靠EJB服務器完成,當JBoss 5在2006變成完全解耦、可肢解時,
我們就可以使用原本只支持EJB的JBoss分布式緩存系統(tǒng)來支持我們的普通JavaBeans了(POJO)。這其中目前可能會花費一些力氣,因為還沒有一個統(tǒng)一的POJO構件接口標準,我相信以后
可能會有。
如果你不想花費力氣,而且可能就只是一臺服務器,可以通過雙核芯片提升性能,那么單態(tài)緩存如果實現?很簡單,使用一個緩存產品如OsCache等,將其設定保存在 Application中,或者在web.xml中進行一下簡單的配置即可。
但是,這時你可能碰到另外一個問題:狀態(tài)的唯一標識,如何通過唯一標識從緩存中那么
多對象狀態(tài)中取出你要的那一個呢?比較瑣碎。
有沒有一個框架幫助你省卻這些麻煩,當然推薦Jdon Framework,只要將包含狀態(tài)的類(主要是Domain Model)繼承特定的類或接口(接口在1.4版本實現)即可,這個類的對象運行時就會被緩存或從緩存中讀取,再也無需你照料緩存了,就這么簡單。
當然,Jdon Framework的底層緩存器是可以被替代,使用你喜歡的緩存產品,因為jdon
Framework是基于Ioc設計,構件之間是完全解耦、可徹底肢解,能夠通過配置替代和更換的。
如果你不明白這個道理,需要好好研究一下Ioc模式帶給我們革命性的新變化。
從以上也可以看出:java復雜性還在于我們需要在編碼時,卻要想象其運行時的情形。而這種翻譯聯想沒有深厚的實踐功底,是很難順利完成的。
狀態(tài)管理中間件
自從J2EE開辟中間件時代以來,就有相當多的高級中間件提供與具體應用無關的通用功能,狀態(tài)管理中間件很早就有之,EJB的有態(tài)Session Bean是一個代表。
一個中間件不但要有良好的松耦合設計,我們暫時稱為靜態(tài)設計;更要有優(yōu)秀的動態(tài)設計,例如狀態(tài)管理就屬于一種動態(tài)設計。
當然,如果你比較謙虛,不但要選擇一些靜態(tài)設計很好的框架或中間件;而且還要依賴一些擁有良好的動態(tài)運行管理的中間件。
EJB無論是EJB1.X/EJB2.X/EJB3.X.在狀態(tài)管理上要更加優(yōu)秀,當然EJB3.X又吸收了優(yōu)秀的靜態(tài)設計概念,但是因為需要有一個具體服務器實現過程,這個過程中存在一些陷阱,如In-Box問題等。
Spring無疑是一個靜態(tài)設計非常優(yōu)秀框架,它一直在AOP上孜孜不倦,力圖探索一條從AOP角度進行動態(tài)運行管理干預捷徑,相信會有驚人結果,當然,這種細粒度的AOP需要實踐檢驗,當然如果整入JDK 6.0就更好。
而Jdon Framework則試圖在目前兩者之間尋求了一個平衡,既有Ioc/AOP優(yōu)秀的靜態(tài)設計,雖然在AOP上不及Spring前衛(wèi);但提供了切實Session和Cache狀態(tài)管理;
如果你不需要EJB的分布式多服務器集群功能;又不是AOP的超級粉絲,無疑使用Jdon Framework之類的框架無疑是簡化方便的。
狀態(tài)設計的難點
最后,我不得不重申,并不是有了良好的狀態(tài)管理框架就可以高枕無憂了,狀態(tài)的設計其實是我們每個項目必須面臨的可變課題,如果狀態(tài)復雜了可以使用狀態(tài)模式對付,可惜往往狀態(tài)不夠復雜。
一個對象本身屬性和狀態(tài)是應該耦合在一起,還是進行分離,屬性和狀態(tài)沒有明顯的涇渭分明的界限,我們舉一個例子:
論壇Forum這個對象,它有一些字段屬性,如論壇名稱、論壇描述,還有其他一些相關屬性:如該論壇的最新發(fā)帖;該論壇的發(fā)貼量,后兩者好像也是論壇字段,但是他們可能經常變化的,應該屬于狀態(tài),那么狀態(tài)和Forum這個主體對象是什么關系?是將該論壇的最新發(fā)帖和該論壇的發(fā)貼量兩個字段并入Forum這個Domain Model中,還是應該單獨建立一個狀態(tài)對象?如果進行分離,分離的依據是什么?
當然,這里分離的依據是因為對象的生存周期不同。對于我們熟悉的課題,我們能夠馬上分辨出其中的生存周期,如果是不熟悉領域的建模呢?
所以,大家已經明白:狀態(tài)設計的難點是:如何粒度細化地創(chuàng)建模型對象;然后分辨出其中動態(tài)的狀態(tài)性質。這是域建模實戰(zhàn)中一個難點。
很多人問我:你提倡的域建模、設計模式和框架是什么意思?為什么說他們是Java開發(fā)設計的三件寶呢?或者說三個典型知識點呢?我想通過本篇我已經通過狀態(tài)這個概念稍微解釋了域建模的一些特點。
當前,MDA中的四色原型模式Archetype將幫助我們更好地分辨出類的屬性、狀態(tài)和行為,這是一場帶來以后十年的軟件革命,詳情請看下面討論。
相關參考:
學生課程評分系統(tǒng)的設計討論
數據庫時代的終結
用j2ee架構金融平臺的問題
DDD(Domain-Driven Design領域驅動設計)實戰(zhàn)
更多關于evans ddd討論
轉載于:https://www.cnblogs.com/bigmouthz/archive/2008/01/15/1040180.html
總結
以上是生活随笔為你收集整理的(转帖)数据库时代的终结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: basis--IMG后台如何显示事务码(
- 下一篇: [Microsoft][ODBC SQL