在開源面向對象數據庫 db4o 之旅 系列文章的第 1 部分:初識 db4o 中,作者介紹了 db4o 的歷史和現狀,應用領域,以及和 ORM 等的比較; 在第 2 部分:db4o 查詢方式中, 作者介紹了 db4o 的三種不同的查詢方式:QBE、SODA 以及 Native Queries,并分別通過這三種不同的途徑實現了兩個關聯對象的查詢。
前面我們已經介紹了如何在 db4o 中查詢以及添加對象,在本文中我們將會向您介紹在 db4o 中如何對對象進行更新以及刪除操作。
?
場景一
我們來設想這樣的場景:一位名叫“張三”的人買了車,并上好了牌照(如本系列第二部分之代碼),而他基本信息的地址并不詳細,只寫了“成都市”,在一次主管部門檢查此人信息的時候,發現了這個問題,并立即著手修改。
在 db4o 中,我們這樣來實現對這個用戶信息的修改(清單1):
package com; import bo.People; import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import com.db4o.query.Predicate; public class DB4OTest{ public static void main(String[] args){ //打開數據庫 ObjectContainer db = Db4o.openFile("auto.yap"); try{ ObjectSet<People> result = db.query(new Predicate<People>() { public boolean match(People people) { return people.getName().equals("張三"); } }); People people = result.next(); //修改地址 people.setAddress("成都市金牛區xxx號"); db.set(people); }finally{ //關閉連接 db.close(); } } } |
修改數據是如此的簡單,通過 NQ 查詢出 People 對象,接著修改其地址,最后保存即可。現在我們來看看修改是否成功, 打開 ObjectManager ,如圖 1 所示,我們可以看到數據庫里的用戶數據已經更新了。
與本系列文章第二部分不同的是,我們利用 ObjectSet<People> result 來獲取返回結果,而不是 List<People> list。查閱 ObjectSet 的 API 我們發現 ObjectSet 實際上繼承了 java.util.List 和 java.util.Iterator。為什么要繼承兩個接口?這是由于 db4o 為了方便開發者而有意這樣設計的,db4o 的設計目標就是輕量級,這樣的繼承方式為 ObjectSet 提供了多種特性,而無需開發者在多個集合接口之間轉換。
場景二
讓我們考慮下面這個場景:
由于工作原因,“張三”要離開省會去其他城市發展,他的汽車也要在那里使用,為了方便,他還是決定重新更換為本地牌照。
這次我們幾乎和場景一采用同樣的代碼,但結果卻不同(清單2):
package com; import bo.People; import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import com.db4o.query.Predicate; public class DB4OTest{ public static void main(String[] args){ //打開數據庫 ObjectContainer db = Db4o.openFile("auto.yap"); try{ ObjectSet<People> result = db.query(new Predicate<People>() { public boolean match(People people) { return people.getName().equals("張三"); } }); People people = result.next(); //修改地址 people.setAddress("綿陽市xx區xxx號"); //修改車牌號 people.getAutoInfoList().get(0).setLicensePlate("川B00000"); db.set(people); }finally{ //關閉連接 db.close(); } } } |
想必應該保存成功了吧,只是多加入了設置車牌的代碼。打開 ObjectManager,如圖 2 所示。很奇怪,地址保存成功了,而車牌卻根本沒變化。
其實這也是 db4o 的有意安排。設想一個復雜對象有很多成員,并且這些成員又有自己的成員。當更新該對象,db4o 將不得不更新其所有的關聯對象、關聯對象的關聯對象,等等。這將引起嚴重的性能懲罰,而且在大部分的情況下是沒有必要這樣的。
db4o 引入了“更新深度(update depth)”這一概念來控制被更新的對象成員樹深度。默認的更新深度是 1,這就意味著只有基本類型和 String 類型的成員變量可以被更新,而修改對象成員將得不到任何反映,例如本例中修改 People 對象的 _autoInfoList 成員。
為了能更新成員對象,ob4o 提供了 cascadeOnUpdate() 方法,該方法必須在每次開啟數據庫之前設置清單3:
package com; import bo.People; import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import com.db4o.query.Predicate; public class DB4OTest{ public static void main(String[] args){ //級聯設置 Db4o.configure().objectClass("bo.People") .cascadeOnUpdate(true); //打開數據庫 ObjectContainer db = Db4o.openFile("auto.yap"); try{ ObjectSet<People> result = db.query(new Predicate<People>() { public boolean match(People people) { return people.getName().equals("張三"); } }); People people = result.next(); //修改地址 people.setAddress("綿陽市xx區xxx號"); //修改車牌號 people.getAutoInfoList().get(0).setLicensePlate("川B00000"); db.set(people); }finally{ //關閉連接 db.close(); } } } |
這下終于如愿以償,如圖 3 所示。其實 db4o 為開發者想得很周到,關鍵是如何用好這些特性。
場景三
“張三”換了工作后,事業發展很快,準備把車賣了換新的,于是他去交管部門辦理移交手續,刪除關聯的車輛信息清單4:
package com; import bo.AutoInfo; import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import com.db4o.query.Predicate; public class DB4OTest{ public static void main(String[] args){ //打開數據庫 ObjectContainer db = Db4o.openFile("auto.yap"); try{ ObjectSet<AutoInfo> result = db.query(new Predicate<AutoInfo>() { public boolean match(AutoInfo ai) { //匹配姓名和車牌號 return ai.getLicensePlate().equals("川B00000") && ai.getOwnerNo().getName().equals("張三"); } }); AutoInfo ai = result.next(); //刪除車輛信息 db.delete(ai); }finally{ //關閉連接 db.close(); } } } |
如圖 4 所示,所關聯的車輛信息已被刪除了。
場景四
在場景三的基礎上修改一下,設想“張三”由于工作不順,導致最后維護汽車的開支都困難,他不得不退出有車一族的行列清單5:
package com; import bo.People; import com.db4o.Db4o; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import com.db4o.query.Predicate; public class DB4OTest{ public static void main(String[] args){ //級聯設置 Db4o.configure().objectClass("bo.People") .cascadeOnDelete(true); //打開數據庫 ObjectContainer db = Db4o.openFile("auto.yap"); try{ ObjectSet<People> result = db.query(new Predicate<People>() { public boolean match(People people) { //匹配姓名 return people.getName().equals("張三"); } }); People people = result.next(); //刪除車主以及關聯的車輛信息 db.delete(people); }finally{ //關閉連接 db.close(); } } } |
用過 Hibernate 的開發者都知道,它的級聯刪除讓人留下了深刻印象,第一次使用的時候都會為之振奮。db4o 也為開發者提供了級聯刪除,和場景二的級聯更新一樣, cascadeOnDelete() 是專門為刪除準備的,基本概念和 cascadeOnUpdate() 一致。打開 ObjectManager 我們會發現數據庫已經清空了,張三的購車經歷到此結束。
?
通過本系列文章,db4o 的優勢已經體現得淋漓盡致,它的添加、更新、刪除是如此的簡單,正如 db4o 的口號那樣——“僅需一行代碼就能存儲復雜結構對象,極大的降低了開發時間和成本,提供高效的性能,無需 DBA 干預”。
如本文有不詳盡之處,大家可以參考官方的《用戶指南》或訪問 db4o 官方中文論壇,db4o 中文社區正在火熱成長!
?
學習
- db4o 官方網站 。
-
面向對象數據庫 db4o 之旅系列
:查看此系列文章完整列表。
-
ODMG 官方網站
:了解 ODMG 技術。
-
developerWorks Java 技術專區
:數百篇關于 Java 編程各個方面的文章。
獲得產品和技術
討論
- db4o 開發者論壇:討論 db4o 技術。
-
developerWorks Java 論壇
:學習 Java 技術。?
?
? | ||
|
![]() |
Rosen Jiang 來自成都,是 db4o 和 OO 的忠實 fans,是 2005 年 db4o 的 dvp 獲得者之一。他正在 J2me 應用中使用 db4o,你可以通過 rosener_722@hotmail.com 和他聯系。 |
![]() |
||
|
![]() |
Chris 來自香港,熱愛開源和 db4o。他創辦了中國最火熱的 Java 和開源社區 Matrix(http://www.Matrix.org.cn), 你可以通過 chris@Matrix.org.cn 和他聯系。 |
![]() |
||
|
![]() |
張黃矚,熱愛開源軟件,熟悉 Java/C/C++ 編程語言,對數據庫技術網絡技術均感興趣。你可以通過 zhanghuangzhu@gmail.com 聯系他。 |
IBM DeveloperWorks(IBM DW) 版權所有!引用、轉貼本文應注明本文來自 IBM DW。