開源面向對象數據庫 db4o 之旅: 深刻db4o

前言html

在開源面向對象數據庫 db4o 之旅 系列文章的第 1 部分:初識 db4o 中,做者介紹了 db4o 的歷史和現狀,應用領域,以及和 ORM 等的比較; 在第 2 部分:db4o 查詢方式中, 做者介紹了 db4o 的三種不一樣的查詢方式:QBE、SODA 以及 Native Queries,並分別經過這三種不一樣的途徑實現了兩個關聯對象的查詢。java

前面咱們已經介紹瞭如何在 db4o 中查詢以及添加對象,在本文中咱們將會向您介紹在 db4o 中如何對對象進行更新以及刪除操做。數據庫

更新數據編程

場景一網絡

咱們來設想這樣的場景:一位名叫「張三」的人買了車,並上好了牌照(如本系列第二部分之代碼),而他基本信息的地址並不詳細,只寫了「成都市」,在一次主管部門檢查此人信息的時候,發現了這個問題,並當即着手修改。jsp

在 db4o 中,咱們這樣來實現對這個用戶信息的修改(清單1):
清單1. 修改地址編程語言

  1.                                
  2. package com;
  3.  
  4. import bo.People;
  5.  
  6. import com.db4o.Db4o;
  7. import com.db4o.ObjectContainer;
  8. import com.db4o.ObjectSet;
  9. import com.db4o.query.Predicate;
  10.  
  11. public class DB4OTest {
  12.  
  13.         public static void main ( String [ ] args ) {
  14.                 //打開數據庫
  15.                 ObjectContainer db = Db4o. openFile ( "auto.yap" );
  16.                 try {
  17.                         ObjectSet<People> result = db. query ( new Predicate<People> ( ) {
  18.                             public boolean match (People people ) {
  19.                                 return people. getName ( ). equals ( "張三" );
  20.                             }
  21.                         } );
  22.                         People people = result. next ( );
  23.                         //修改地址
  24.                         people. setAddress ( "成都市金牛區xxx號" );
  25.                         db. set (people );
  26.                 } finally {
  27.                         //關閉鏈接
  28.                         db. close ( );
  29.                 }
  30.         }
  31. }

 

修改數據是如此的簡單,經過 NQ 查詢出 People 對象,接着修改其地址,最後保存便可。如今咱們來看看修改是否成功, 打開 ObjectManager ,如圖 1 所示,咱們能夠看到數據庫裏的用戶數據已經更新了。
圖1. 修改地址
圖1. 修改地址性能

與本系列文章第二部分不一樣的是,咱們利用 ObjectSet<People> result 來獲取返回結果,而不是 List<People> list。查閱 ObjectSet 的 API 咱們發現 ObjectSet 實際上繼承了 java.util.List 和 java.util.Iterator。爲何要繼承兩個接口?這是因爲 db4o 爲了方便開發者而有意這樣設計的,db4o 的設計目標就是輕量級,這樣的繼承方式爲 ObjectSet 提供了多種特性,而無需開發者在多個集合接口之間轉換。學習

場景二網站

讓咱們考慮下面這個場景:
因爲工做緣由,「張三」要離開省會去其餘城市發展,他的汽車也要在那裏使用,爲了方便,他仍是決定從新更換爲本地牌照。

此次咱們幾乎和場景一採用一樣的代碼,但結果卻不一樣(清單2):
清單2. 修改地址和車牌(不成功)

  1.                                
  2. package com;
  3.  
  4. import bo.People;
  5.  
  6. import com.db4o.Db4o;
  7. import com.db4o.ObjectContainer;
  8. import com.db4o.ObjectSet;
  9. import com.db4o.query.Predicate;
  10.  
  11. public class DB4OTest {
  12.  
  13.         public static void main ( String [ ] args ) {
  14.                 //打開數據庫
  15.                 ObjectContainer db = Db4o. openFile ( "auto.yap" );
  16.                 try {
  17.                         ObjectSet<People> result = db. query ( new Predicate<People> ( ) {
  18.                             public boolean match (People people ) {
  19.                                 return people. getName ( ). equals ( "張三" );
  20.                             }
  21.                         } );
  22.                         People people = result. next ( );
  23.                         //修改地址
  24.                         people. setAddress ( "綿陽市xx區xxx號" );
  25.                         //修改車牌號
  26.                         people. getAutoInfoList ( ). get ( 0 ). setLicensePlate ( "川B00000" );
  27.                         db. set (people );
  28.                 } finally {
  29.                         //關閉鏈接
  30.                         db. close ( );
  31.                 }
  32.         }
  33. }

 

想必應該保存成功了吧,只是多加入了設置車牌的代碼。打開 ObjectManager,如圖 2 所示。很奇怪,地址保存成功了,而車牌卻根本沒變化。
圖2. 修改地址和車牌(不成功)
圖2. 修改地址和車牌(不成功)

其實這也是 db4o 的有意安排。設想一個複雜對象有不少成員,而且這些成員又有本身的成員。當更新該對象,db4o 將不得不更新其全部的關聯對象、關聯對象的關聯對象,等等。這將引發嚴重的性能懲罰,並且在大部分的狀況下是沒有必要這樣的。

db4o 引入了「更新深度(update depth)」這一律念來控制被更新的對象成員樹深度。默認的更新深度是 1,這就意味着只有基本類型和 String 類型的成員變量能夠被更新,而修改對象成員將得不到任何反映,例如本例中修改 People 對象的 _autoInfoList 成員。

爲了能更新成員對象,ob4o 提供了 cascadeOnUpdate() 方法,該方法必須在每次開啓數據庫以前設置清單3
清單3. 修改地址和車牌(成功)

  1.                                
  2. package com;
  3.  
  4. import bo.People;
  5.  
  6. import com.db4o.Db4o;
  7. import com.db4o.ObjectContainer;
  8. import com.db4o.ObjectSet;
  9. import com.db4o.query.Predicate;
  10.  
  11. public class DB4OTest {
  12.  
  13.         public static void main ( String [ ] args ) {
  14.         //級聯設置
  15.                 Db4o. configure ( ). objectClass ( "bo.People" )
  16.         . cascadeOnUpdate ( true );
  17.                 //打開數據庫
  18.                 ObjectContainer db = Db4o. openFile ( "auto.yap" );
  19.                 try {
  20.                         ObjectSet<People> result = db. query ( new Predicate<People> ( ) {
  21.                             public boolean match (People people ) {
  22.                                 return people. getName ( ). equals ( "張三" );
  23.                             }
  24.                         } );
  25.                         People people = result. next ( );
  26.                         //修改地址
  27.                         people. setAddress ( "綿陽市xx區xxx號" );
  28.                         //修改車牌號
  29.                         people. getAutoInfoList ( ). get ( 0 ). setLicensePlate ( "川B00000" );
  30.                         db. set (people );
  31.                 } finally {
  32.                         //關閉鏈接
  33.                         db. close ( );
  34.                 }
  35.         }
  36. }

 

這下終於如願以償,如圖 3 所示。其實 db4o 爲開發者想得很周到,關鍵是如何用好這些特性。
圖3. 修改地址和車牌(成功)
圖3. 修改地址和車牌(成功)
刪除數據

場景三

「張三」換了工做後,事業發展很快,準備把車賣了換新的,因而他去交管部門辦理移交手續,刪除關聯的車輛信息清單4
清單4. 刪除車輛

  1.                                
  2. package com;
  3.  
  4. import bo.AutoInfo;
  5.  
  6. import com.db4o.Db4o;
  7. import com.db4o.ObjectContainer;
  8. import com.db4o.ObjectSet;
  9. import com.db4o.query.Predicate;
  10.  
  11. public class DB4OTest {
  12.  
  13.         public static void main ( String [ ] args ) {
  14.                 //打開數據庫
  15.                 ObjectContainer db = Db4o. openFile ( "auto.yap" );
  16.                 try {
  17.                         ObjectSet<AutoInfo> result = db. query ( new Predicate<AutoInfo> ( ) {
  18.                             public boolean match (AutoInfo ai ) {
  19.                                 //匹配姓名和車牌號
  20.                                 return ai. getLicensePlate ( ). equals ( "川B00000" )
  21.                                            &amp;&amp; ai. getOwnerNo ( ). getName ( ). equals ( "張三" );
  22.                             }
  23.                         } );
  24.                         AutoInfo ai = result. next ( );
  25.                         //刪除車輛信息
  26.                         db. delete (ai );
  27.                 } finally {
  28.                         //關閉鏈接
  29.                         db. close ( );
  30.                 }
  31.         }
  32. }

 

圖 4 所示,所關聯的車輛信息已被刪除了。
圖4. 刪除車輛信息
圖4. 刪除車輛信息

場景四

在場景三的基礎上修改一下,設想「張三」因爲工做不順,致使最後維護汽車的開支都困難,他不得不退出有車一族的行列清單5
清單5. 刪除全部信息

  1.                                
  2. package com;
  3.  
  4. import bo.People;
  5.  
  6. import com.db4o.Db4o;
  7. import com.db4o.ObjectContainer;
  8. import com.db4o.ObjectSet;
  9. import com.db4o.query.Predicate;
  10.  
  11. public class DB4OTest {
  12.  
  13.         public static void main ( String [ ] args ) {
  14.         //級聯設置
  15.                 Db4o. configure ( ). objectClass ( "bo.People" )
  16.         . cascadeOnDelete ( true );
  17.                 //打開數據庫
  18.                 ObjectContainer db = Db4o. openFile ( "auto.yap" );
  19.                 try {
  20.                         ObjectSet<People> result = db. query ( new Predicate<People> ( ) {
  21.                             public boolean match (People people ) {
  22.                                 //匹配姓名
  23.                                 return people. getName ( ). equals ( "張三" );
  24.                             }
  25.                         } );
  26.                         People people = result. next ( );
  27.                         //刪除車主以及關聯的車輛信息
  28.                         db. delete (people );
  29.                 } finally {
  30.                         //關閉鏈接
  31.                         db. close ( );
  32.                 }
  33.         }
  34. }

 

用過 Hibernate 的開發者都知道,它的級聯刪除讓人留下了深入印象,第一次使用的時候都會爲之振奮。db4o 也爲開發者提供了級聯刪除,和場景二的級聯更新同樣, cascadeOnDelete() 是專門爲刪除準備的,基本概念和 cascadeOnUpdate() 一致。打開 ObjectManager 咱們會發現數據庫已經清空了,張三的購車經歷到此結束。

結論

經過本系列文章,db4o 的優點已經體現得淋漓盡致,它的添加、更新、刪除是如此的簡單,正如 db4o 的口號那樣——「僅需一行代碼就能存儲複雜結構對象,極大的下降了開發時間和成本,提供高效的性能,無需 DBA 干預」。

如本文有不詳盡之處,你們能夠參考官方的《用戶指南》或訪問 db4o 官方中文論壇,db4o 中文社區正在火熱成長!

參考資料

學習

得到產品和技術

討論

做者簡介

  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 聯繫他。
相關文章
相關標籤/搜索