Java與數據庫應用JDBC
Java發明以來在短短的幾年之間迅速占領了從桌面應用(JSE)到服務器(JEE)再到小型設備嵌入式系統(JME)的應用開發市場其語言吸取了SmallTalk的一切皆對象的理念擺脫了C++的歷史累贅簡潔自由的風格贏得了很多開發者的喜愛從JDK開始Java成為實用的語言而不是被人觀望的新品秀再經過JDK的大量增強(尤其是Collection Framework)JDK的虛擬機效率提升(HotSpot)JDK的融合百家之長(LoggingRegExpNewIO等)現在已經是成熟穩重頗顯大家風范
在企業級市場上大部分的應用建立在數據庫基礎上數據是企業的生命傳統開發語言包括面向過程的C面向對象的C++變種Pascal的Delphi(非常棒的語言我用過四年)面向數據的PowerBuilder等等先後在數據庫開發的舞台上展現風姿Java當然不會放過這些於是出現了JDBC在JDBC的幫助下Java也迅速滲入數據庫開發的市場尤其是面向企業服務器的應用開發
今天要談的JDO與JDBC有非常密切的關系盡管JDO並不是只面向JDBC的數據對象包裝規范下面先簡單地介紹一下JDBC
關系數據庫之百家爭鳴ODBC
關系數據庫的歷史一言難盡我只能從我的接觸經歷和所見所聞簡單地敘述一下最早的時候計算機還只在一些大型的研究機關露面並不是普羅大眾可以涉及的蘋果電腦將個人電腦引入民間再隨著IBM的PC標准開放個人電腦逐步普及開來加上微軟的DOS操作系統以及Borland的Turbo系列語言開發環境老百姓發現原來電腦可以做這麼多事!後來出現了DBASE一個簡單的關系數據庫系統和SQL語言後來Borland看到了數據庫的市場前景推出了Paradox(也是當今Delphi和C++Builder中仍然使用的Paradox)一舉占領了民用數據庫的大部分江山之後Borland干脆收購了Dbase後來又購買了InterBase將數據庫市場的領先優勢一直保持到Windows出現這時候微軟在Windows和被人痛罵之後頑強地推出以及更穩定的和WinAPI造就了個人電腦桌面操作系統的霸主地位在Borland未警覺的情況下購買了同樣具有類Dbase數據庫技術的Fox公司並迅速將其易用化形成了FoxBase後來演變成FoxPro逐漸超過了Borland成為個人電腦數據庫的大戶微軟再接再勵為簡單易用而低負荷要求的數據庫應用開發了Access贏得了廣大開發人員的心當然同期的OracleSybaseInformix等商用數據庫憑專注於企業級數據庫技術成為高端的幾位領軍人物微軟當然也想成為高端數據庫供應商之一於是自行開發一套面向企業級應用的數據庫不過很快項目夭折微軟不甘心購買了Sybase的底層TDS技術包裝成了SQL Server憑微軟的高度易用性的特點也占領了不少市場
當市場上出現眾多的數據庫產品之後Borland和微軟都發現自己擁有的數據庫產品挺多市場也不小不同的產品給用戶帶來不同的配置任務不利於所有產品的推廣於是兩者紛紛開始制定數據庫訪問的規范微軟推出了ODBC其面向開發人員的親和性逐步獲得了認可同時Borland糾集了IBM和Novell也推出了IDAPI數據庫接口規范也就是今天BDE的核心不過後來Novell和IBM先後退出只剩Borland獨力支撐不過Borland是一個技術實力雄厚的公司其技術一向領先於微軟BDE的性能比初期的ODBC不知道要好多少倍後來微軟偷師學藝把連接池等技術加到ODBC中在Delphi及其BDE在市場上風光無限的時候逐步趕了上來並有超過直到今天BDE仍是Borland的產品線上的數據庫訪問標准而微軟如果不是將ODBC和多數數據庫的客戶端內嵌進Windows的話估計BDE仍是市場的贏家不過微軟是玩弄市場的老手通過對操作系統的壟斷其數據庫產品和ODBC標准終究占據了多數開發市場
從optional pack到JDK的標准API
Java開始涉及數據庫應用後Sun就極力制定Java的數據庫規范JDBC API就是類似ODBC一樣對數據庫訪問的底層協議進行最基本的包裝然後形成一套統一的數據訪問接口數據庫連接SQL語句句柄結果集都帶有ODBC的影子以方便配置為目的Sun極力推薦完全瘦客戶端的TYPE 型JDBC驅動這是一個不需要安裝數據庫客戶端的驅動規范是現在使用最多的當然為了保持與舊的數據庫兼容JDBC規范中包括了專用於連接ODBC的TYPE 驅動和需要安裝數據庫客戶端的TYPE 驅動以及可以由廠商在數據庫服務端專門提供面向JDBC的服務的TYPE 驅動
JDBC最早出現時還不屬於標准JDK的一部分而是作為一個額外包提供下載後來隨著Java編寫的數據庫應用的的增多和JDBC規范本身的逐漸成熟JDBC終於成為JDK的一部分
JDBC目前最新的是版本還有正在討論中的版本實際上在開發中使用得最多的還是中的API中主要增加了可雙向滾動的結果集更新批處理等提高可用性和性能的API主要增加了連接池可更新的結果集等特性將在可管理性連接池規范化等方面再做改進
面向對象與數據庫
現在的程序員沒有不知道面向對象的作為接近真實客觀世界的開發概念面向對象使程序代碼更易讀設計更合理在普遍存在的數據庫應用領域開發人員對面向對象的追求從未停止過從八十年代開始就有很多公司和研究機構在進行著面向對象與數據庫結合的研究
SmallTalkC與C++DelphiObject PascalJava
面向對象的語言最早有好幾種雛形IBM的SmallTalk是其中最為流行的在SmallTalk中一切都是對象一切都是類它將面向對象的概念發揮到了極致面向對象的編程比起傳統的面向過程的方式挺進了一大步使人們認識到原來軟件可以這樣寫不過由於計算機基本結構與底層硬件體系和系統軟件的限制SmallTalk還不能在理想的性能前提下推廣到普通的應用上這一點暫時限制了SmallTalk的發展接著C語言的面向對象版C++出現了由於使用C語言的人很多C++很快成為面向對象編程的主流語言不過為了保證與C的兼容C++保留了很多面向過程的痕跡比如惡心的指針全局變量等等Pascal的改進版Object Pascal相對來說安全許多後來Borland干脆將Object Pascal換了個名字叫Delphi從此開創了一片面向對象編程的新世界 Delphi的嚴謹語法和快速編譯吸引了眾多的應用開發者加上Borland的完美的VCL組件體系比起MFC來方便而容易另外Delphi完整的數據庫組件也將數據庫開發變得簡單而容易Delphi再次成為成熟的面向對象開發語言微軟當然不會放過這些通過將MFC內置到操作系統中微軟的VC++也搶回一些市場這也是為什麼Delphi開發的應用程序編譯後會比VCVB開發的程序大的原因
年Sun的一個開發小組本來為了小型嵌入式系統開發OAK語言結果無心插柳柳成蔭發展出了Java語言它是一個完全擺脫了傳統語言的各種負擔的面向對象的語言當然也保留了一些非面向對象的核心(原始類型)以保證速度現在Java也為最流行的面向對象語言之一當然微軟同樣不會放過它擅於模仿的微軟立即弄出一個C#來與之競爭並在C#中保留了一些變種的指針(指代)以吸引傳統的C開發者關於這些語言的各自特點這裡就不一一贅述了
數據庫與數據對象化
數據庫是企業級應用不可缺少的因此在面向對象流行的時候數據庫廠商也在進行著數據對象化的研究這些研究在上個世紀八十年代就初現端倪
數據庫的對象化一般有兩個方向一個是在主流的關系數據庫的基礎上加入對象化特征使之提供面向對象的服務但訪問語言還是基於SQL另一個方向就是徹底拋棄關系數據庫用全新的面向對象的概念來設計數據庫這就是對象數據庫ODBMS
關系數據庫對象化SQL與JDBC
隨著許多關系數據庫廠商開始提供對象化服務各自的接口開始互不兼容在經歷一些麻煩之後關系數據庫廠商感覺到規范化的必要因為當初關系數據庫雄霸天下時SQL標准起了很大作用大家可以按照統一的編程方式來訪問高性能的商用數據庫
關系數據庫廠商集中起來重新將對象化服務規范起來形成了SQL規范將其中的對象結構等內容規范起來開始一個嶄新的面向對象的關系數據庫(ORDBMS)的歷程
JDBC就是在這種情況下出台的它將對關系數據庫中的對象服務的訪問API規范起來為Java平台提供了訪問ORDBMS的標准方式當然JDBC對傳統的SQL操作也進行了很多功能增強
Oracle是一個傳統的關系數據庫廠商在對象化的道路上Oracle當然采取追加對象化特征的道路以侵入數據對象化的市場保持Oracle在數據庫領域的領導地位如果說Oracle使Oracle走向全盛的話從Oracle開始Oracle就成為關系數據庫加對象類型的先驅在Oracle中我們可以定義一些數據結構(Record)將普通的類型包裝在其中成為數據元素然後可以在客戶端按Record結構進行訪問初步提供了面向對象的數據庫服務
對象數據庫
對象數據庫就是采用全新的面向對象概念來設計數據庫的全新數據庫類型在這方面主要以一些大學研究機構進行設計和開發有些也形成了產品不過由於市場方面的原因(主要是關系數據庫的容易上手和市場絕對領導地位)和ODBMS先天的一些弱點(比如查詢引擎很難優化)使ODBMS沒有象關系數據庫那樣流行起來
不過對象數據庫的對象化特點還是令人割捨不下目前還是有一些很好的產品在市場上從商用的到免費的都用目前在ODBMS領域占據領導地位的是VersantFastObjects和ObjectStore等幾大廠商並且市場份額也在逐步擴展免費的產品包括C++編寫的Ozone純Java的dbo等等還有一些研究機構開發一些底層的面向對象數據庫引擎但只提供一些底層的API不提供管理方面的功能以及一些算法提供開放式接口讓廠商去選擇和實現比如美國威斯康新大學計算機系數據庫組的SHORE引擎就是一個非常出色的面向對象數據庫引擎現在還在積極的更新中一些其它研究機構和數據庫廠商采用它完成了自己的特別的對象數據庫比如專用於地理信息的數據庫專用於宇宙空間數據研究的數據庫等等
目前對象數據庫最大的障礙是缺乏統一的規范各個數據庫廠商有各自的訪問接口對象數據庫比起關系數據庫來不只是基本的幾種數據類型那麼簡單它還涉及繼承處理多態等一大堆面向對象特征的實現規范化道路當然困難重重這也是對象數據庫無法普及的一個重要原因
也有一些機構提出了一些建議的規范比如制定Corba標准的OMG小組的一個分組ODMG提出的ODMG規范目前已經是版本其中的OQL對象查詢語言相當具有吸引力還有一些中立的機構提出了其它的一些標准化的對象訪問API也可算是面向對象數據庫的規范之一象前面提到的FastObjects和Ozone就是符合ODMG規范的
Java對象映射
話說回來在一般的開發人員眼中數據庫就是指關系數據庫因此很多應用還是采用簡單的JDBC來訪問數據庫在開發的過程中大家逐漸感覺到JDBC的局限性比如調用復雜容易產生資源洩漏等等與面向對象的Java語言有一段距離因此很多開發小組開始思考如何將應用中的數據進行對象化建模然後再想辦法與JDBC結合起來這就是Java數據庫開發中的層出不窮的對象包裝技術
對象包裝技術
傳統包裝與演變
傳統包裝顧名思義就是最初出現的包裝方式很多公司都經歷過這一步產生了很多風格各異的包裝方法當然筆者也有過還算豐富的嘗試過程
舉例來說如果我們有一個用戶類
public class User {
public int userId;
public String name;
public javautilDate birthday;
}
我們可以將其當作一個簡單的數據類然後寫一些工具方法來實現與JDBC的交互這些方法我們可以放到一個另外的工具類中也可以放到User類中作為靜態方法這些方法包括簡單的增刪改查(以Oracle為例)
public class User {
public int userId;
public String name;
public javautilDate birthday;
public static User addUser(String name Date birthday) throws SQLException {
Connection conn = …; //獲取一個JDBC連接
PreparedStatement ps = connprepareStatement(…); // 獲取一個序列值來作為用戶標識
ResultSet rs = psexecuteQuery();
rsnext();
User user = new User();
useruserId = rsgetInt(); //讀取序列值為新用戶標識
username = name;
userbirthday = birthday;
ps = connprepareStatement(insert into …); //插入用戶數據記錄的SQL
pssetInt(userid);
pssetString(username);
pssetDate(userbirthday);
psexecuteUpdate();
rsclose();
psclose();
connclose();
return user;
}
public static void deleteUser(int userId) throws SQLException {
Connection conn = …;
//…
}
public static User getById(int userId) throws SQLException {
//…
}
//…
}
以上就是一個簡單的數據包裝的基本雛形我們可以看到這是一個非常簡單的JDBC包裝一些代碼可以模塊化以實現重用另外這段代碼還有很大隱患就是中途如果出現異常的話就會使系統出現JDBC資源漏洞因為JDBC分配的資源(connpsrs等)是不能被Java虛擬機的垃圾回收機制回收的因此我們的addUser方法就需要改成下面的樣子
public static User addUser(String name Date birthday) throws SQLException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = new User();
try {
conn = …; //獲取一個JDBC連接
ps = connprepareStatement(…); // 獲取一個序列值來作為用戶標識
rs = psexecuteQuery();
rsnext();
useruserId = rsgetInt(); //讀取序列值為新用戶標識
username = name;
userbirthday = birthday;
ps = connprepareStatement(insert into …); //插入用戶數據記錄的SQL
pssetInt(userid);
pssetString(username);
pssetDate(userbirthday);
psexecuteUpdate();
} finally {
//這裡注意一定要按照創建的順序關閉JDBC資源
if(rs != null) try { rsclose(); } catch(SQLException ex) { exprintStackTrace(); }
if(ps != null) try { psclose(); } catch(SQLException ex) { exprintStackTrace(); }
if(conn != null) try { connclose(); } catch(SQLException ex) { exprintStackTrace(); }
}
return user;
}
所有的數據庫訪問方法都必須進行這樣的包裝當我們的數據類達到一定的數量後(比如十幾個幾十個)這些方法占據了大量的代碼維護困難出現BUG機會增多並且不易排錯尤其是資源漏洞這種容易引起服務器穩定性問題的BUG
為了保持數據類的純潔我們可以將JDBC操作方法集中到一個公共工具類中去完成這樣這個工具類會非常龐大但每個數據類會變得很簡單這種方式可以稱作是DataAccessObject模式相當於EJB中的ValueObject是脫離數據庫細節的純對象模型
這些都是最基本的存儲處理在基本增刪改查(這裡的查指按關鍵字查找對象)的基礎上我們還需要進行復雜的匹配查詢(SQL)這使得我們的存儲處理代碼進一步復雜化簡單地我們可以寫一個類似的方法
public static Collection findBy(String sql) throws SQLException {
//… (這裡獲取JDBC連接)
Collection col = new Vector();
ps = connprepareStatement(sql);
rs = psexecuteQuery();
while(rsnext()) {
User user = new User();
useruserId = rsgetInt();
username = rsgetString();
userbirthday = rsgetDate();
coladd(user);
}
return col;
//… (同前這裡是清理JDBC資源的代碼)
}
這就是一個查詢接口的基本定義查詢采用的語言仍是SQL
如果我們需要將參數從SQL串中獨立出來以節省數據庫的解析時間並規范化我們還需要將查詢條件作為參數傳遞到這個方法中去方法的接口改為
public static Collection findBy(String sql Object[] params) throws SQLException {
//…
ps = connprepareStatement(sql);
for(int i = ; i < paramslength; i++) pssetObject(i+params[i]);
//…
}
調用的時候sql參數中會包含一些?號如
select IDNAMEBIRTHDAY from USER where … = ? and … > ? and …
當然也有一些開發團隊喜歡將所有可能的查詢都寫死成一個個的專用查詢方法在其中完成對應的SQL操作這一點類似於EJBQL只不過是將EJBQL中容器實現的功能通過手工編碼來實現這樣做使得查詢受到限制但可以提供更保險的接口
還有一些開發人員看到每個類中寫這樣一些查詢方法使得這個類的代碼變得龐大維護麻煩便將所有的查詢方法放到一個公共的工具類中去只是在方法中再加入一個參數Class cls來表示需要查詢哪個對象使得每個數據類變得緊湊一些當然這樣的結果是那個公共類變得異常龐大誰維護誰倒霉可以說是犧牲一人幸福團隊不過如果這個人心理素質不夠好壓力承受能力不強的話一些對數據類的改動可能會受到他的阻礙這時候就是一夫當關萬夫莫開
現在我們已經實現了基本對象的包裝現在才能開始考慮更多的問題首先我們可能會從規范化的角度出發給每一個屬性加上讀寫訪問器getter/setter在前面的User類中可能我們會將基本屬性部分寫為
public class User {
private int userId;
private String name;
private Date birthday;
//以下是針對以上屬性的getter/setter一般可以用IDE工具生成
public int getUserId() { return userId; }
public void setUserId(int value) { userId = value; }
public String getName() { return name; }
public void setName(String value) { name = value; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date value) { birthday = value};
//…
}
這樣一個比較規范的數據類包裝就算完成了
另外我們知道面向對象概念中一個屬性可以是另一個對象也就是說對象之間是存在著引用關系的這種關系還分為一對一一對多多對多等幾種情況從一個既定對象出發其某個屬性可以是另一個對象也可以是包含另一組對象的集合那麼在我們的數據包裝裡面當然最好也能方便地處理對象之間的關系假定現在我們又有一個數據類Group
public class Group {
public int grouId;
public String groupName
public Set users; //set of User
}
這裡為了簡單表明含義暫不采用getter/setter
而User對所屬的Group有一個引用
public Group belongTo;
在這裡UserbelongTo和Groupusers就是一個一對多的關系
在我們的數據類中如何才能實現數據庫的存取呢?就算是不考慮Groupusers這個反向關系光是UserbelongTo就是一件頭疼的事如果我們在取出一個User對象時同時將其Group對象也取出來可以保證不會在訪問某個用戶的組時得到一個null不過這樣有幾個缺點
數據類的存取處理(JDBC)變得復雜需要執行很多SQL讀取才行有時候只需要訪問User的基本屬性時浪費時間和資源尤其是對集合型屬性的預讀取更加可怕
如果按這個邏輯雙向的關系處理變得危險很容易陷入死循環如果要避免必須在類代碼中加入一些特別的機制也是很麻煩的事
如果對象之間的關系是更復雜的情況下比如三個四個對象之間互相關聯那就是一場噩夢對代碼的編寫和維護都異常艱難
於是很多開發人員自然而然地退後一步在User類中只保留一個groupId並不保存Group對象這樣可以將UserbelongTo屬性變成int類型而另外寫一個getter方法
public Group getBelongTo() {
return GroupfindById(belongTo);
}
而在Group類中干脆將users屬性去掉只保留一個方法
public Set getUsers() {
return new HashSet(UserfindBy(select … from USER where BELONG_TO=?new Object[]{ new Integer(groupId) }));
}
也許細心一點的讀者已經看出來了這裡的幾個方法都沒有將SQLException捕捉也沒有在方法中聲明也就是說是有語法錯誤的因為SQLException不是一個RuntimeException不錯確實是這樣不過我們這裡為了簡單明了起見省掉這些處理以更直接清楚地表達意思
這樣實際上我們的對象關系包裝已經名存實亡在類的內部有很多用於訪問所引用對象的復雜代碼這些已經違背了我們將對象關系保持的初衷有些開發人員甚至不在類中保留訪問關系對象的方法而是在客戶調用時再去訪問另一對象類的讀取方法如
…
User user = UsergetById(…);
//對user對象進行一些訪問如顯示其姓名等等
Group group = GroupfindById(userbelongTo);
//對group對象進行一些訪問如顯示組名等等
…
在這樣的代碼裡實際上我們已經從根本上退回了關系數據庫的出發點這與直接訪問數據表有多大區別呢?只不過是在表上面套了一層貌似面向對象的皮而已不幸的是這種方式還存在於很多應用之中
從前面提到的這些面向對象包裝的細節問題我們可以看到這種傳統包裝方式的一些主要的缺陷
數據庫命名與對象設計命名的一致性問題
很多時候我們興致勃勃地設計好一個類圖並且經過評審之後開始對它進行數據庫包裝這時候發現有些屬性名在具體的數據庫中與該數據庫的關鍵字沖突不能用作表名或字段名必須在數據表設計時采用另外的名稱或者很麻煩地加上引號來使用於是寫數據庫處理代碼的人有意見了他必須很清楚地記得一個屬性在類中是什麼屬性名在表中又是什麼字段名在編寫的類逐漸增多後尤其是一個類經過歷次變動之後或者經過很長時間又需要改動並去處理這些JDBC代碼時代碼維護人員簡單要發瘋了!
對象的查詢仍局限於SQL
這一點也是這種簡單的包裝方法最不能擺脫關系數據庫的地方上面也已經說過一些命名沖突帶來了很多維護工作量代碼中必須還保留數據表的命名體系而不是對象類的命名體系這將使調用人員仍需要清楚記得兩套命名體系無論時間經過多久或者開發人員是否有流動
此外對於普遍需要用到的連表查詢也給應用開發帶來困難這些地方仍不能突破SQL的限制
SQL資源占用多
在處理對象集合訪問或者處理集合類型屬性時往往我們只能在同一個Connection中處理一切事務這就要求一次性地將集合中的對象全部讀入如果集合很大的話容易造成數據庫擁塞使得性能大打折扣適得其反這方面的優化也是很多開發人員一直在努力改進的
對象關系處理復雜
前面提過對象之間的關系處理上普通的包裝技術是一種表面上的處理在訪問時調用者仍需要用大量的代碼進行處理並且這還只是讀取在寫入關系屬性時會有更多的細節問題需要處理
面向對象特色只能應用一小部分
面向對象的包裝到前面所說的為止都還只是很基本的處理而面向對象的精華繼承和多態在這裡得不到任何幫助我們放棄了很多合理的設計來遷就數據庫的包裝
以上就是基本數據包裝的主要缺陷還有更多的小問題也需要額外的處理
不過有責任心的開發人員當然不會就此善罷甘休他們冥思苦想可能會用更好的方式來實現對象之間關系的處理而且還會加入一些延遲訪問的機制將對象之間的引用在需要用的時候才去連接數據庫取數據另外在類的繼承上他們也試圖去在數據庫包裝上得到體現
值得感謝的是一些富有經驗的團隊在經歷若干改進之後毫不吝惜將他們的成果貢獻出來並將其獨立化成為可復用的組件這也就是後來出現的對象包裝產品包括商用的和免費的
產品化包裝中間件
面向對象的包裝產品化後逐步推廣開來稱作關系/對象映射O/R Mapping並且在產品化的過程中產品提供者在產品中逐漸提供了更多的功能先是一些自動命名轉換器得以應用將客戶代碼中的類名屬性名在內部處理的時候自動地轉換到對應的數據庫結構命名空間上這樣應用開發的時候不再關心具體的數據庫結構不再需要記憶不同地命名體系只需要一心一意地根據類圖來進行開發在此之後這些O/R Mapping產品的開發團隊又向前邁了一大步引入了詞法分析器提供面向對象的查詢語言!很多對象關系的查詢使應用開發變得非常方便使O/R Mapping產品上了一個新的台階
TopLink
TopLink是一個非常早期的產品最初面向C++後來也實現了Java的映射TopLink性能優異功能強大並且提供了獨特的查詢過濾器機制以及對關系的處理和查詢都非常有效於是TopLink逐漸從商用化O/R Mapping產品中勝出成為市場上的最出色的映射產品也正因為這一點最大的關系數據庫廠商Oracle將其收購成為提供最強數據庫和最強對象映射中間件的廠商
CastorHibernate
TopLink雖然強大但太強大的東西免不了得意忘形TopLink開始將用戶鎖死到自己的產品上查詢方式是最突出的它的查詢體系含有很多別扭的概念(在我看來是如此)但為達到一般O/R產品不能達到的功能開發者只能接受這些慢慢地也產生積怨再加上其高昂的價格讓很多新老用戶望而卻步於是免費的產品開始崛起
免費的O/R Mapping工具有很多種這裡只提其中最有影響力的兩種Castor和Hibernate
Castor是Exolab組織開發的面向Java的包裝工具它最大的特色就是實現了大部分的ODMG OQL規范在查詢上可以象完全使用一個對象數據庫一樣類圖進行查詢(後面會有介紹)它的原理是通過Java反射API去實現屬性的設置和讀取不過由於各種原因Castor後來的版本更新越來越慢最終停步在之前成為至今未出到正式版的O/R Mapping產品不管怎麼樣它還是一個相當不錯的產品
Hibernate是一個現在很火熱的O/R Mapping產品目前已經出到版它功能一樣強大同樣使用Java反射API進行對象的設置但它的查詢語言就是一套比較獨特的體系這一點有點類似TopLink但Hibernate更具有親和力對關系的查詢更方便只不過比起Castor來在方便性和規范性上還是稍遜一籌就目前狀況而言Hibernate的用戶量和技術支持要強一些
面向對象的數據庫查詢
在對數據庫進行面向對象研究的過程中軟件世界的開發人員和設計人員們發現對數據庫能夠進行對象化的查詢才是對數據庫進行徹底的面向對象化這體現在我們使用一種全新的數據庫查詢語言能夠很簡潔易懂地對數據庫中的對象進行查詢一個典型的例子如下
假設我們已經有前面提到的兩個數據類User和Group它們之間有一對多的關系UserbelongTo和Groupusers在數據庫中已經存在很多這兩個類的實例以及相互之間的關系我們可以使用下面的對象式查詢語言來查詢符合條件的User對象
select * from User where UserbelongToname=GROUP
或者
select userIdname from User where UserbelongToname=GROUP
等等從中我們可以看出通過使用面向對象中的成員屬性指定符可以讓我們達到SQL中的連表的效果實際上第一個句查詢的SQL等價版本是
select a* from USER a GROUP b
where aBELONG_TO = bGROUP_ID
and bNAME = GROUP
由此可見對象式的查詢語言比起實現同樣功能的SQL語言來說簡單了很多意義也更明確更符合使用者的思維習慣在類圖比較復雜查詢涉及的類又比較多的時候這種新型的查詢語言體現出絕對的優勢
ODMGOQLJava Binding
在面向對象式查詢語言的研究過程中開發人員們逐漸實現了相似的查詢語言然後互想取長補短最終在ODMG組織()的統一下形成了規范化的語言ODMG OQL這是一種完全面向對象的數據庫查詢語言語法與前面提到的類似不過考慮了更廣泛的情況語句更加簡潔而嚴謹
OQL並不是針對某種語言的它可以被應用到很多種開發語言中它不象SQL那樣只是純字符串式的查詢語句因為面向對象查詢中還必須提供相關類的信息所以OQL需要在編程語言中實現一些特定的API
目前ODMG的OQL已經被規范化地應用到SmallTalkJavaC++這些面向對象的程序設計語言當中在ODMG的規范中這幾個模塊被稱作SmallTalk BindingJava Binding和C++ Binding
不過由於歷史原因ODMG並沒有象想象中地那樣得到廣泛應用現有的十幾個面向對象數據庫中采用ODMG OQL規范的少之又少目前也只有FastObjecctsOzone這些產品采納了這個規范而象Versant這樣的大廠商還沒有采取OQL來查詢數據庫而是自己定義了自己的一套API稱作VQL(Versant Query Lanaguage)
在JDO之前的O/R Mapping產品中也有一些產品使用OQL(有時候是其子集)比如CastorApache的Jakarta小組開發的OJB等等
第三方協議
軟件世界是一個多姿多彩的世界總有那麼一些好事之士不斷地冒出新奇的想法還有一些開發面向對象數據庫的組織制定了自己的一套對象式數據庫查詢語言自己的規范
不過這些規范相對來說影響力小得多比起ODMG來可以說應用范圍太小更不用說與SQL這樣廣泛應用的標准進行比較了
EJBQL
Sun為了使Java應用在企業級數據庫應用中不遺余力地推廣JEE在年的時候推出了EJB規范其中包含了富有特色的面向CMP方式的EntityBean的查詢語言EJBQL功能類似於ODMG OQL只不過只能在EJB發布時靜態地存在於應用描述符中不能在程序中動態地使用這是EJBQL最大的弱點也許EJB規范會將其動態化但到了那一天世界多半已經不是現在的樣子了
JDO
JDO中有最近規定的一個對象式查詢語言規范稱作JDOQL比起OQL來JDOQL將查詢語言中的很多元素與Java語言緊密地結合在一起有的人覺得麻煩有些人覺得規范評論各不相同從筆者個人的角度來看這樣有利於沒寫過數據庫應用沒用過SQL的新手很快地習慣JDOQL但實際上有多少人會在沒寫過SQL沒了解過關系數據庫的情況下去用JDO寫數據庫應用呢?畢竟市場說明了一切個人認為JDO中對數據庫對象的查詢多少顯得有些累贅如果能更簡化一點那將更吸引使用傳統SQL的開發人員
JDO歷程與主要產品
說起JDO其來由還有一段特殊的背景Java語言在JDK達到比較實用的目的後企業級數據庫應用也正是軟件開發市場中的重要組成部分Sun看到這一點後也希望通過Java這個強大的武器在數據庫開發市場攻占市場份額JDK推出後Sun同時推出了面向企業應用的EJB對基於java的中間件服務器框架進行了規范化定義這就是JEE不過在JDK時Java的速度還是不能與傳統的C/C++和Delphi這樣一些應用開發語言相比為了防止業界對Java的激情因此而消退Sun宣布將在JDK中加入強大的虛擬機技術HotSpot其中包含更先進的垃圾收集算法和更優化的Java字節代碼再編譯技術(相當於JITJava即時編譯技術)HotSpot引起了Java關注者的極大興趣但Sun的HotSpot一拖再拖最後包含在JDK中出來時性能也沒有象預期的那樣好比起C++編譯生成的代碼來還是有一段距離
這個時候大家開始對Sun心存懷疑而Sun深知這一點於是將公眾的注意力趕緊轉移到EJB上從EJB到EJB再到EJB業界又開始關注JEE中間件技術上來很快開發人同發現用EJB來編寫數據庫應用還是有很大的難度雖然在分布式技術上EJB確實有很大的價值在這個時候Sun決定推出JDO技術作為輕量級的Java數據庫訪問規范而這一點也受到很多傳統O/R Mapping市場的歡迎為了與傳統O/R Mapping有所區別Sun一開始就高姿態地將JDO定位成不只是面向關系數據庫的Java規范而是針對所有的存儲技術包括面向對象數據庫和其它類型的存儲體系(如文件)就象EJB EntityBean一樣雖然就筆者的角度這個做法使第一版的JDO拋棄了很多傳統O/R Mapping提供的面向關系數據庫的功能可以算是一個失策
規范提出JSR
JDO最早是由Sun召集眾多的O/R Mapping開發團隊集中起來共同提出的首先是通過會議確定了JDO需要包括的內容然後正式提出一個Java規范請求(JSR)正式開始了JDO規范的制定下面是主要的進展裡程碑
JSR # approved in July
組建的專家小組包括SunAppleBEAIBMOracleSAPWebGain等
完成公開評論草案
在JavaOne上引入
最終草案
最終草案公布
在JavaOne上啟動
最終草案
版正式公布
修正版
規范啟動
…
Oracle與JDO
作為JDO專家組的重要成員同時作為最大的關系數據庫廠商的Oracle地位顯然非同一般在JDO規范中Oracle也可說是立下汗馬功勞很多API的形成Oracle都提供了很重要的參考意見最終的投票Oracle也是毫不猶豫
可是世間的事總是變化莫測的就在JDO快出台之時Oracle收購了TopLink這一點使Oracle的身份變得特殊而復雜TopLink是一個商業產品是以商業利益為目標的而Oracle也是追求利益最大化的典型商家這一點與JDO的開放精神背道而馳因此我們看到後期Oracle對JDO的不積極態度甚至在前一陣的JavaOne大會上有人從Oracle的角度非正式地攻擊JDO
主要產品以及各自特點
在JDO規范制定的同時出現了幾個主要的JDO產品有美國的基於對象數據庫的FastObjects j法國的支持Versant對象數據庫文件數據庫主流RDBMS的LiDO南非的JDOGenie德國的JRelay等等這些都是很不錯的JDO產品下面列舉一下我對主要的幾個產品的印象
LiDO(法國LibeLis公司)
我對JDO的認識主要是通過LiDO這個產品它在年月的一份圖文並茂的教程中簡要解說了JDO的使用和優點這個教程可以在這裡下載LiDO的特色是大而全支持文件型數據庫RDBMSODBMS甚至是XML數據庫不過配置較麻煩最新版本是RC
KodoJDO(美國Solarmetrics公司)
Kodo是JDO的中流砥柱之一在JDO還未最後通過的時候它就是一個比較成熟的產品了其特點是注重性能和穩定性目前最新版本是是客戶最多的產品
JDOGenie(南非HemSphere公司)
這是目前我最推薦的產品最新版本是性能也不錯穩定性還有待驗證但它有一個最大的特點集成性好最易學其公司的CTO David Tinker也是一個善解人意的年輕人采納了很多網友的意見對產品進行改進主要是在配置上非常方便有一個專門的圖形界面工具可以進行配置數據庫生成對象查詢等等很實用的功能
JRelay(德國ObjectIndustries公司)
這也是一個出現得比較早的產品也有一個GUI工具用於配置曾幾何時這個工具還是相對很方便的但一年多過去了好象沒什麼進展最新版本是我試過一段時間後來就沒有再跟進了
FrontierSuite for JDO (美國ObjectFrontier)
這個產品與JRelayKodo一起可算是早期的JDO三個主要產品它支持正向開發和反向開發(Reverse Engineer)它的特色是反向工程(從表結構生成數據類)比較方便與UML的結合也很強不過真正運行起來的時候配置復雜
TJDO(一群跨國界的有志之士)
這是一個在Sun提供的參考產品(Reference Implementation)的基礎上加入一些擴展功能而形成的一個免費產品目前最新版本是beta不過進展也緩慢這個版本已經出現好幾個月了沒有進一步的更新
目前狀況與未來展望
從年月JDO規范正式公布以來各個產品層出不窮從商業到免費的層次都有不錯的產品推出象KodoLidoJDOGenie等產品都已經比較成熟可以考慮投入開發使用在年月JDO又推出修正版修正了版規范中的一些文字錯誤以及輕微地改進了部分異常定義不過改動都不大從現在的情形來看除了Kodo有一些大學的項目用到外好象還沒看到多少使用JDO作開發的應用
JDO畢竟是一個新技術從概念上到實際應用上對其掌握的用戶還不多而這些產品在配置使用上的方便性易用性還有待大幅度改進因此真正用JDO來開發項目的用戶還廖廖無幾至少我還不知道有哪些項目使用了JDO我自己也嘗試使用JDO來開發項目但由於一些JDO版本中還不夠完善的一些硬傷(比如不支持關系數據庫統計功能)使我對JDO仍處於觀望階段
在八月中旬進行的JDO規劃會議中來自各國的各個JDO產品廠商JDO技術咨詢公司JDO研究機構的代表匯聚一堂將各自收集到的用戶對JDO的需求總結起來提出一個個的新的議題並且確定了每個議題的JDO規范撰寫負責人比如高級fetchGroup特性由目前實現得最好的JDOGenie的CTO David Tinker負責關於managedrelationship特性由Kodo的產品總監負責用戶要求最多的JDO對象與PersistenceManager的脫鉤/重掛鉤特性由Sun的Craig Russell親自操刀等等
最具有吸引力的JDO議題筆者個人認為是專門為關系數據庫設立的子規范JDO/R這也是我一直以來最關心的這將使目前JDBC的開發將可以被JDO完全取代並且保證開發過程保持面向對象的特色還有一些將一個類映射到多個表之類的特性也在規范化的列表上這將有利於DBA在不影響應用開發的前提下根據需要更改數據表結構實現更好的性能類似的新特性還有很多粗略地看這些都規范化起來後真不知道各個廠商還能做什麼樣的擴展特性也許以後廠商之間拼的只能是技術支持服務和產品性能了當然最後還有價格的競爭
說了這麼多我想大家關心的還是JDO到底什麼時候能出來我們什麼時候可以用上它什麼時候有中文版產品價格到底如何這些問題目前筆者還無法一一回答只能根據筆者所掌握的信息初步解釋一下據前幾天的JDO啟動大會上David Jordan的預期JDO正式版將在個月後正式完成那正式完成後廠商什麼時候才能提供符合規范的產品呢?這個問題不用擔心因為規范在制定的過程中會不斷地公布公眾預覽版(Public Review)這樣廠商可以先實現其中的功能等規范正式完成後也不會有太大的變化廠商也不會需要太多時間來跟進最終規范所以我估計一年之後我們就可以在JDO上進行開發了至於價格如何規范的產品初步印象是每個開發人員需要一個License一個License大概美元如果JDO產品的價格還保持這麼貴的話(至少對中國用戶來說)我們也還有很多免費(如JPOXTJDO)或半免費(如JCredo)產品可以選擇最後一個關於中文版的問題有待於廠商對中國市場的考察或者看看是否有國內的JDO產品了不過在JDO規范制定的同時我們可以先集眾人之力將其普及使廣大的使用Java語言進行數據庫開發的開發人員都來認識JDO了解JDO甚至將其用到項目開發之中
也許JDO的目標已經吸引了Java世界以外的人微軟發現了這一點也立即計劃在NET體系中加入一個仿照JDO的中間件具體是采用ObjectStore的產品ObjectStore是一個同時做JDO和NETDO(姑且使用這個名稱)的公司
在這裡筆者可以大膽地預測在未來的一兩年內JDO將在Java世界大放光彩!
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26556.html