日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入db4o

發(fā)布時間:2023/12/14 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入db4o 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
這是Rick Grehan發(fā)表在 TheServerSide上的一篇關(guān)于面向?qū)ο髷?shù)據(jù)庫--db4o的文章 ,較全面地介紹了db4o的關(guān)鍵特性,希望對大家認(rèn)識db4o能有所幫助。(2007.12.07最后更新)

??? db4o-針對對象的數(shù)據(jù)庫-是一個完全的對象數(shù)據(jù)庫;它以使對象在其生命周期中-無論是在數(shù)據(jù)庫內(nèi)或是在外-都保持著它們的本性這樣一種方式操縱對象。不論類的復(fù)雜性如何,對象的內(nèi)容,結(jié)構(gòu)和關(guān)系都能夠被保存。
??? 更準(zhǔn)確地說,db4o是一個數(shù)據(jù)庫引擎,你只要將它的一個jar文件包含到你的數(shù)據(jù)庫應(yīng)用的類路徑中就可以使用它了(至少對于Java是這樣的)。所以,db4o運(yùn)行在與你的應(yīng)用程序相同的進(jìn)程空間中,并能被直接地調(diào)用;它不需要類似于在ODBC或JDBC中使用的驅(qū)動文件。db4o存在針對Java,.NET和Mono的版本;它們在功能上都彼此相等。(事實(shí)上,使用.NET創(chuàng)建的db4o數(shù)據(jù)庫也能由Java程序訪問;反之亦然。)
??? db4o是開源的。可執(zhí)行文件,源代碼和文檔可從http://www.db4objects.com/中下載。廣泛的例子程序,和一個活躍的用戶社區(qū)一樣,也都可以從這個站點(diǎn)中找到。
??? db4o最引人的特性之一就是它在簡易性與強(qiáng)大的功能之間的顯著平衡。一方面,它的API是如此地易于掌握和方便使用,即使是初學(xué)者也能在相同的時間內(nèi)創(chuàng)建一個功能完備的數(shù)據(jù)庫對象。另一方面,這些相同的API也提供了更底層的能夠深入調(diào)用數(shù)據(jù)庫引擎的方法,以允許核心開發(fā)者為了得到適當(dāng)?shù)男阅芏苌钊氲皆撘娴膬?nèi)部中去調(diào)整db4o的工具。
??? db4o的特性就是最好的證明--這勝過只是討論--所以我們將通過示例這種方法去證明db4o。然而,我們必須牢記本文通篇只是展示了db4o特性中的一部分罷了。感興趣的朋友會發(fā)現(xiàn)為了知曉該數(shù)據(jù)庫引擎的全部功能而去查閱db4o的文檔所花的時間是值得的。

db4o基礎(chǔ)
??? 讓我們以初學(xué)者使用db4o時可能會做的事情開始:定義了一些類,然后持久化這些類的對象。我們所假定的類為同樣也是假定的QA項(xiàng)目做一個跟蹤測試的系統(tǒng)。我們的系統(tǒng)由兩個類組成,首先是TestSuite類:
??? public class TestSuite {
??????? private String name;? // Test Suite name
??????? private String description;
??????? private String configuration;
??????? private char overallScore;
??????? private ArrayList <TestCase> cases;
??????? private long dateExec;
??????? ... <remainder of TestSuite definition> ...
??? }
??? TestSuite是TestCase對象的容器,(一個測試用例就是一個可單獨(dú)執(zhí)行的測試程序--相關(guān)的測試用例組合成一個測試組)。測試組使用額外的,全局的數(shù)據(jù)成員,每個數(shù)據(jù)成員的用途也是相對明顯的:configuration記錄被測試的指定系統(tǒng);overallScore是對整個測試組一個簡要的評分('P'代表通過,'F'代表失敗,'B'代表被阻塞,等等。);dateExec是一個毫秒級的域,標(biāo)識該測試組被執(zhí)行時的日期與時刻。是ArrayList對象的cases含有單個的測試用例,由TestCase類定義:
??? public class TestCase {
??????? private String name;
??????? private String comment;
??????? private char status;
??????? private long duration;
??????? private float result;
??????? ... <remainder of TestCase definition> ...
??? }
??? 每個測試用例都有一個名稱,形式自由的注釋字段,狀態(tài)(通過或失敗),持續(xù)時間和結(jié)果(例如,為了與測試-字節(jié)/秒的吞吐量-的任意數(shù)據(jù)關(guān)聯(lián))。
??? 因?yàn)槲覀兯P(guān)注是db4o的使用,所以我們不想在描述這些類的使用細(xì)節(jié)上停留。就讓我們簡單地說,我們已經(jīng)執(zhí)行了一個特別地測試組中所有的測試用例,將測試的結(jié)果存放在一個TestSuite對象中(與TestCase對象相關(guān)的ArrayList對象cases中),然后關(guān)閉數(shù)據(jù)庫。是不是太容易了。
??? // Create the database
??? new File("testsuites.YAP").delete();
??? ObjectContainer db = Db4o.openFile("testsuites.YAP");
??? // Store the TestSuite object
??? db.set(testsuite);
??? // Close the database
??? db.close();
??? 就是它。彈指一揮間,你就已經(jīng)做到了。(當(dāng)然,為了保持簡潔,我們?nèi)サ袅藙?chuàng)建TestSuite對象和它的TestCase組件的細(xì)節(jié))
??? 停下來想想上述代碼做了什么事情。特別要考慮你沒有看到的--db4o已經(jīng)做了但還未被告之的事情。
??? 首先,我們不需要告訴db4o任何關(guān)于TestSuite類的結(jié)構(gòu)的信息;不需要我們的幫助,db4o就能發(fā)現(xiàn)這個結(jié)構(gòu)。利用Java反射機(jī)制的能力,db4o測定TestSuite類的結(jié)構(gòu),并勾勒出該類的裝配方式以推導(dǎo)出此類對象的成員與關(guān)鍵數(shù)據(jù)。
??? 第二,我們不必建議db4o去關(guān)注ArrayList。不僅我們不必將ArrayList的大小告訴db4o,而且我們也不必把它里面的內(nèi)容告訴db4o。正如db4o在它剛接觸testsuite對象時就能夠發(fā)現(xiàn)它所需要的一切,db4o也能知道它所需要的關(guān)于(在ArrayList中的)TestCase對象的所有信息。
??? 結(jié)果就是,如果我們把testsuite作為一個任意寵大而復(fù)雜的對象樹的根,db4o能找到并存儲整個樹而不需要我們的任何協(xié)助。所以,存儲這個處于根部的對象testsuite也就是存儲了整個ArrayList對象。
??? 最后,我們也沒有必須要求db4o以事務(wù)的保護(hù)性方式去調(diào)用set方法。任何會修改ObjectContainer(表示數(shù)據(jù)庫的db4o對象)的調(diào)用都會自動地開啟一個事務(wù),除非已經(jīng)有一個活躍的事務(wù)了。此外還會調(diào)用close方法去終止這個事務(wù),所以上述代碼等價于:
??? db.startTransaction();
??? db.set(testsuite);
??? db.commitTransaction();
??? db.close();
??? 此處的startTransaction和commitTransaction方法是為了證明我們的觀點(diǎn)而虛構(gòu)的。db4o也確實(shí)有顯示地提交或中止事務(wù)的方法,但為了使原先的代碼足夠的簡潔我們沒有使用這些方法。db4o隱式的事務(wù)使得數(shù)據(jù)庫能夠一直處于一致的狀態(tài);一旦commit方法已經(jīng)執(zhí)行了,數(shù)據(jù)庫的完整性就能夠得到保證,甚至是發(fā)生了災(zāi)難性失敗也能如此。

查詢I - QBE
??? 有了已經(jīng)存于數(shù)據(jù)庫中的對象,下一步我們想要展示的操作將肯定就是查詢和恢復(fù)。db4o提供了三種查詢API:有一種簡單,有一種優(yōu)雅,還有一種則復(fù)雜。每一種API都有其所長,并適用于不同的查詢條件。以db4o的眼光來看,你選擇哪一種API并沒有關(guān)系:它們都是可兼容的。
??? 我們以簡單的API開始:query by exampel(QBE)。
??? 使用QBE是如此的容易:為你的查詢目標(biāo)構(gòu)建一個'模板'對象,然后把它傳入ObjectContainer的query方法。實(shí)際上,你就是告訴db4o'去拿到所有與這個對象看起來一樣的對象'。(這與JavaSpaces查詢API非常相似;為了清楚地了解如何處理基本數(shù)據(jù)類型,可以看下面的內(nèi)容,db4o的處理方式與JavaSpaces不同。也要注意,JavaSpace Entry對象期望使用public字段,db4o則沒有這種要求。)
??? 假設(shè)一個測試組名為"Network Throughput",我們想取出這個測試組執(zhí)行的所有測試以便我們能確定失敗了的測試所占的百分比(基于TestSuite的overalScore值)。使用QBE,完成該工作的代碼如下:
??? // Open the database
??? ObjectContainer db = Db4o.openFile("testsuites.YAP");

??? // Instantiate the template object, filling in
??? // only the name field
??? testTemplate = new TestSuite("Network Throughput");

??? // Execute the query
??? ObjectSet result = db.get(testTemplate);
??? fails = 0.0f;
??? total = 0.0f;

??? // Step through results,
??? while(result.hasNext())
??? {
??????? testsuite = (TestSuite)result.next();
??????? if(testsuite.getOverallScore()=='F')
??????? fails += 1.0f;
??????? total += 1.0f;
??? }

??? if(total == 0.0f)
??????? System.out.println("No tests of that type found.");
??? else
??? {
??????? System.out.println("Percent failed: " + (fails/total * 100.0f) + "%");
??????? System.out.println("Total executed: " + total);
??? }
??? db.close();
??? 在上面的代碼中,testTemplate是QBE的模板對象。注意,只有它的name字段有真實(shí)的值;所有其它的成員變量不是為null就是為0。Null或0字段不參與QBE查詢;因此,調(diào)用db.get方法就會返回在該數(shù)據(jù)庫中name字段匹配"Network Throughput"的所有TestSuite對象。匹配的TestSuite對象將返回在一個ObjectSet結(jié)果對象中。上述代碼遍歷該結(jié)果,取出對象,然后計算結(jié)果并展示出來。
??? QBE明顯的優(yōu)點(diǎn)就是它的簡易性。不需要掌握其它單獨(dú)的查詢語言。另外,QBE也是類型安全的:你不需要創(chuàng)建一個類似于SQL的查詢語句
??? SELECT TestSuite.overallScore FROM TestSuite WHERE TestSuite.name = 200.0
??? 另一方面,由于該查詢是由Java代碼創(chuàng)建的,編譯器不會允許你把一個浮點(diǎn)值賦給一個String字段;反之亦然。
??? QBE明顯的缺點(diǎn)就是它只能執(zhí)行"等于"查詢。另外,QBE使用null值去確定不參與查詢的String或?qū)ο笠贸蓡T變量,使用0值去指定不參與查詢的數(shù)字字段。所以,例如,我不能發(fā)明一個QBE查詢?nèi)カ@得所有result字段的值為0的TestCase對象。
??? 更為精細(xì)的查詢要求一個能力更強(qiáng)的查詢機(jī)制,而db4o恰恰就有這樣一種機(jī)制。

查詢方式II - 原生查詢(Native Query)
??? db4o的原生查詢系統(tǒng)應(yīng)該是能想像得到的最具彈性的查詢機(jī)制。不像使用數(shù)據(jù)庫查詢語言去構(gòu)建查詢,你是使用"無格式的普通Java語句"去構(gòu)造原生查詢。原生查詢用兩種手段去實(shí)現(xiàn)這件不可思意的工作:一個是Predicate類;另一個是QueryComparator接口。這個類包含一個可重載的(overrideable)回調(diào)方法,該方法將指定如何從數(shù)據(jù)庫中選擇對象(如果你愿意,你將會看到查詢語句的主體....)。這個接口只聲明了一個方法,該方法用于指明如何對查詢結(jié)果進(jìn)行排序。
??? 作為一個例子,我們假設(shè)想找到在給定的一周內(nèi)執(zhí)行過了的總得分為"failed",但與之關(guān)聯(lián)的測試用例中有超過一半的被評為"passed"的測試組。這不是一個簡單的"等于"查詢,所以它不能使用QBE構(gòu)建。
??? 然而,db4o的原生查詢可以直接地生成該查詢。首先,我們繼承db4o的Predicate類:
??? // Predicate class sub-class for native query example
??? public class NativeQueryQuery extends Predicate<TestSuite>
??? {
??????? ObjectContainer db;
??????? private long startdate;
??????? private long enddate;

??????? // 構(gòu)造器要在本地獲得ObjectContainer對象和日期范圍
??????? public NativeQueryQuery(ObjectContainer _db,
??????????? long _start, long _end)
??????? {
??????????? db = _db;
??????????? startdate = _start;
??????????? enddate = _end;
??????? }

??????? // 這就是查詢的主體
??????? public boolean match(TestSuite testsuite)
??????? {
??????????? float passed;
??????????? float total;
??????????? TestCase testcase;

??????????? // 判斷testsuite是否在指定的日期范圍內(nèi)
??????????? if(testsuite.getDateExec()<startdate ||
????????????? testsuite.getDateExec()>enddate) return false;

??????????? // 如果該測試組對象中沒有測試用例對象,則拒絕將該測試組對象放入查詢結(jié)果中
??????????? if(testsuite.getNumberOfCases()==0)
??????????????? return false;

??????????? // 檢查該測試組對象中的測試用例的通過率是否超過50%
??????????? passed = 0.0f;
??????????? total = 0.0f;
??????????? for(int i=0; i<testsuite.getNumberOfCases(); i++)
??????????? {
??????????????? testcase = testsuite.getTestCase(i);
??????????????? if(testcase.getStatus()=='P')
??????????????????? passed+=1.0f;
??????????????? total+=1.0f;
??????????? }
??????????? if((passed/total)<.5) return false;
??????????????? return true;
??????? }
??? }
??? 注意在這個類的使用中使用了Java泛型語義,這就是告訴db4o只去取TestSuite對象。當(dāng)查詢執(zhí)行時,TestSuite對象就會傳入match方法(我們之前提到過的回調(diào)方法),如果傳入的TestSuite對象符合查詢規(guī)范該方法就返回true,否則就返回false。
??? match方法中的代碼首先確定侯選對象是否是在一周的日期范圍內(nèi)。如果是,則循環(huán)該對象中的成員變量測試用例的對象,計算出所有通過了的測試用例的總數(shù)。如果,得到的通過率小于50%,該測試組就被拒絕;否則,就讓它通過。
??? 我們可以使用如下的代碼準(zhǔn)確地展示該查詢程序:
??? . . .
??? TestSuite testsuite;
??? NativeQueryQuery nqqClass;
??? Date now;

??? // Open the database
??? ObjectContainer db = Db4o.openFile("testsuites.YAP");

??? // Instantiate a NativeQueryQuery object,
??? // setting the start and end dates for
??? // any test in the past week
??? // 604800000 = milliseconds in a week
??? now = new Date();
??? nqqClass = new NativeQueryQuery(db,
??? now.getTime()-604800000L,
??? now.getTime());

??? // Execute the query and display the
??? // results
??? System.out.println("Results:");
??? ObjectSet results = db.query(nqqClass);
??? if(results.isEmpty())
??????? System.out.println("? NOTHING TO DISPLAY");

??? while(results.hasNext())
??? {
??????? testsuite = (TestSuite)(results.next());
??????? System.out.println(testsuite.toString());
??? }

??? db.close();
??? . . .
??? 可以把原生查詢想像成這樣:目標(biāo)類的對象一個接一個從數(shù)據(jù)庫中取出,然后把它們傳入match方法中。只有那些被match方法返回true的對象才會置于查詢結(jié)果ObjectSet對象中。基本上可以說,如果你會知道如何寫Java代碼,那么你就知道如何寫原生查詢。
??? 那么排序呢?如果想按日期的升序排列查詢結(jié)果,我們就要實(shí)現(xiàn)QueryComparator接口,如下所示:
???public class NativeQuerySort implements QueryComparator<TestSuite>{
??????? public int compare(TestSuite t1, TestSuite t2)
??????? {
??????????? if (t1.getDateExec() < t2.getDateExec()) return -1;
??????????? if (t1.getDateExec() > t2.getDateExec()) return 1;
??????????? return 0;
??????? }
????}
compare方法的作用十分明顯。那些在查詢中得以勝出的對象會成對的傳入compare方法,如果第一個對象會排在第二個對象之前,相同或之后的位置,該方法就會分別返回一個小于,等于或大于0的值。為了準(zhǔn)確地說明對查詢結(jié)果的排序,我們實(shí)例化NativeQuerySort,并把對query方法的調(diào)用修改成如下:
??? . . .
??? // Instantiate the sort class
??? nqsClass = new NativeQuerySort();
??? . . .
??? ObjectSet results = db.query(nqqClass, nqsClass);
??? . . .
其它的代碼仍然與原先的保持一致。
??? 好懷疑的讀者可能會抱怨道,原生查詢只是一種編程上的小伎倆--相比較于直接去拿到所有的TestSuite對象然后再排除其中不符合條件的對象這樣的程序,原生查詢并不快。
???是的,但并不十分準(zhǔn)確。原生能夠被優(yōu)化。你所需要做的只是把兩個jar文件--db4o-xxx-nqopt.jar(xxx表示db4o的版本)和bloat.jar--置于CLASSPATH環(huán)境變量中。在查詢執(zhí)行的時候,這些類庫中的代碼會對(在match方法中)例如基本數(shù)據(jù)類型比較,算術(shù)和布爾表達(dá)式,簡單的對象成員訪問,以及更多方面的結(jié)構(gòu)進(jìn)行優(yōu)化。這個被支持的優(yōu)化的列表在不停的增長,因?yàn)閐b4o引擎還在擴(kuò)展優(yōu)化的范圍。

查詢方式III - S.O.D.A.
??? db4o獨(dú)一無二的能力之一就是它的API被分層了。開發(fā)者能夠選擇通過高層次--賦予數(shù)據(jù)庫引擎相當(dāng)大的自由度,讓它決定如何去實(shí)現(xiàn)它的操作--或者開發(fā)者也可以使用一種更直接地方式去訪問db4o。后一種選擇為程序員平添了更多的負(fù)擔(dān),程序員必須更加小心地引導(dǎo)數(shù)據(jù)庫引擎的內(nèi)部工作。但回報就是得到一個更快,能力更強(qiáng)的數(shù)據(jù)庫應(yīng)用。
??? db4o的S.O.D.A.(Simple Object Data Access)查詢機(jī)制就是該層次API的一個完美的例子。S.O.D.A.就是db4o的內(nèi)部查詢系統(tǒng)--QBE和原生查詢都被翻譯成了S.O.D.A.。然而,應(yīng)用程序也能直接地調(diào)用S.O.D.A.。
??? 假設(shè)我們想找到所有名為"Network Throughput",且至少擁有一個其result字段--我們使用這個參數(shù)作為字節(jié)/秒的量度--不小于指定值(比方說,100)的測試用例的測試組。為該請求而做的S.O.D.A.查詢可能就像這樣:
??? . . .
??? TestSuite testsuite;

??? // Open the database
??? ObjectContainer db = Db4o.openFile("testsuites.YAP");

??? // Construct the query
??? Query query = db.query();
??? query.constrain(TestSuite.class);
??? Constraint nameConst = query.descend("name").
??? constrain("Network Throughput");
??? query.descend("cases").descend("result").
??? constrain(100.0f).smaller().and(nameConst);

??? System.out.println("Results:");
??? // Execute the query
??? ObjectSet result = query.execute();
??? if(result.isEmpty())
??? System.out.println("NOTHING TO DISPLAY");

??? while(result.hasNext())
??? {
??????? testsuite = (TestSuite)(result.next());
??????? System.out.println(testsuite.toString());
??? }

??? db.close();
??? . . .
??? 在由Illustration 1所示圖表的幫助下,這些有點(diǎn)兒神秘的代碼就變得不那么神秘了。該程序所構(gòu)建的歸總起來就是一個用于指導(dǎo)底層數(shù)據(jù)庫引擎的查詢圖(Query Graph)。descend方法創(chuàng)建了該圖的一個分支,該分支向下步入對象的結(jié)構(gòu)中。每個descend方法就在這個樹中構(gòu)建一個結(jié)點(diǎn),可以在這些結(jié)點(diǎn)上再附上一個約束(使用constrain方法)。用SQL的話來說,約束指定了查詢的"WHERE"子句部分。多個約束可以在與(and)或或(or)方法的協(xié)助下結(jié)合起來。在上面的查詢中我們已經(jīng)使用了and方法去關(guān)聯(lián)這些約束。
????????????????????????????????????
與其它的查詢方式一樣,查詢結(jié)果返回到ObjectSet對象中,通過遍歷該對象就可取出那些拿到的對象。
??? 注意,由于S.O.D.A.是一種低層次的訪問方法,沒有智能的指示,它就沒有默認(rèn)的行為。訪問cases對象的成員變量result字段的代碼很簡單
??? query.descend("cases").descend("result"). ...
我們并沒有告訴S.O.D.A."cases"是一個集合對象。所以當(dāng)查詢執(zhí)行時,它會不被察覺地檢測ArrayList對象cases中所有元素(TestCase對象)的result字段,然后會正確地返回那些擁有符合搜索規(guī)范的測試用例的測試組。

db4o性能調(diào)優(yōu)
??? 我們已經(jīng)展示了db4o的基本操作(但無關(guān)緊要的刪除操作除外,下面將會提到它)。但,正如我們在本文通篇所提到的,db4o發(fā)布(expose)了一個API層次結(jié)構(gòu),以允許開發(fā)者能夠選擇以何種層次的API去控制建立在該數(shù)據(jù)庫引擎之上的應(yīng)用程序。從另一方面看,如果你所想做的只是向數(shù)據(jù)庫存入,及從數(shù)據(jù)庫取出對象,那么你就已經(jīng)看到了你所需要的一切。然而,如果你的應(yīng)用的需求超出了添加,更新,查詢和刪除,可能還有一個db4o的特性可解決你的問題。
??? db4o的ObjectContainer實(shí)際上發(fā)布(expose)了兩個API。第一個API非常的簡單,由十個方法組成。這些方法處理數(shù)據(jù)庫的打開與關(guān)閉;添加,更新,查詢和刪除對象;及提交或中止事務(wù)。短言之,該API為你提供了在操縱數(shù)據(jù)庫時所需要所有功能。然而,該API中的一個方法--ext()--是進(jìn)入"被擴(kuò)展的"ObjectContainer的一個入口。該被擴(kuò)展的ObjectContainer為深入控制db4o的內(nèi)部發(fā)布(expose)了更多方法。例如,你可以獲得并改變數(shù)據(jù)庫的配置上下文,使用它你能夠修改該引擎的行為。
??? 例如,假設(shè)你已經(jīng)從數(shù)據(jù)庫中拿到了一個TestSuite對象,發(fā)現(xiàn)該對象中的數(shù)據(jù)是錯誤的,并決定該對象應(yīng)該被刪除。此外,你還決定你必須刪除的不僅是該TestSuite對象,而且還有所有與之關(guān)聯(lián)的TestCase對象(在ArrayList對象cases中)。
??? 你是可以冗長而乏味地遍歷這個ArrayList對象,一個接一個地刪除每一個TestCase對象,然后再刪除TestSuite對象本身。可能一種更好的解決方案是為這個TestSuite對象啟用db4o的"級聯(lián)刪除"特性。
??? . . .
??? // Fetch the database's configuration context
??? Configuration config = db.ext().configure();
??? // Get the ObjectClass for TestSuite
??? ObjectClass oc = config.objectClass("testsuites.TestSuite");
??? // Turn on cascaded delete
??? oc.cascadeOnDelete(true);
??? ...? ...
??? db.delete(ts1);
??? . . .
在上述代碼中,我們實(shí)例化了一個ObjectClass對象,該對象使我們能夠訪問到TestSuite對象的db4o內(nèi)部表現(xiàn)形式。我們打開cascadeOnDelete標(biāo)記,以便當(dāng)執(zhí)行db4o.delete(ts1)時,不僅ts1對象會被刪除,而且所有由ts1引用的TestCase對象也會被刪除。(由于顯而易見的原因,默認(rèn)情況下,級聯(lián)刪除是被關(guān)閉的)
??? 作為另一個例子,假設(shè)你想為數(shù)據(jù)庫預(yù)分配存儲空間,以至于要最小化磁盤驅(qū)動器的頭移動(head movement)。(最好是在硬盤碎片整理之后,并新創(chuàng)建一個數(shù)據(jù)庫時這樣做。)并且假設(shè)以O(shè)bjectContainer對象db作為打開了的數(shù)據(jù)庫:
??? // Fetch the database's configuration context
??? // 獲得數(shù)據(jù)庫的配置上下文
??? Configuration config = db.ext().configure();
??? // Pre-allocate 200,000 bytes
??? // 預(yù)分配200000000字節(jié)
??? config.reserveStorageSpace(200000000L);
把數(shù)據(jù)庫文件預(yù)擴(kuò)展到200000000字節(jié)(略小于200兆字節(jié))。假設(shè)該磁盤已經(jīng)做碎片整理了,那么被分配的塊就是連續(xù)的,這可顯著提升數(shù)據(jù)庫的訪問。

db4o高級應(yīng)用
??? 完全可以說,db4o在它不大的空間(約500K)內(nèi)已裝入了足夠多的特性,相比較于db4o在運(yùn)行過程中所做的眾多事情,我們不能花費(fèi)更多的筆墨去解釋它們了。但是有兩個特性十分突出,以至于肯定要提到它們。
??? db4o的對象復(fù)制實(shí)現(xiàn)了被總稱為面向?qū)ο蟀娴臄?shù)據(jù)庫同步。使用復(fù)制所提供的功能,你能為一個數(shù)據(jù)庫中的一個對象做一個副本,并將該副本放入另一個數(shù)據(jù)庫中。使用這樣的方法,副本對象就無形中和原始對象關(guān)聯(lián)在了一起。對任一對象--原始對象或副本對象--的改變都會被跟蹤到,以便在之后的某個時候,數(shù)據(jù)庫能夠被重組,并且這兩個數(shù)據(jù)庫中對象的不同之處可被分解(例如,可同步這兩個數(shù)據(jù)庫)。
??? 它工作起來就像這樣:為使一個數(shù)據(jù)庫可被復(fù)制,與事務(wù)計數(shù)器一樣,該數(shù)據(jù)庫中被創(chuàng)建的任何一個對象都用一個唯一全局標(biāo)識符(UUID)進(jìn)行了標(biāo)記。當(dāng)你從原始數(shù)據(jù)庫中"復(fù)制"一個對象到另一個數(shù)據(jù)庫中,副本對象會帶著與它的原始對象相同的UUID和事務(wù)計數(shù)器。副本數(shù)據(jù)庫現(xiàn)在就可以從它的原始數(shù)據(jù)庫那兒弄走了。修改副本對象的內(nèi)容將會導(dǎo)致對象的事務(wù)計數(shù)器被修改。所以,當(dāng)這兩個數(shù)據(jù)庫重新連接起來,db4o內(nèi)建的同步處理機(jī)制就能一個對象一個對象地進(jìn)行正確的匹配(使用UUID),并確定原始或副本對象是否已經(jīng)改變了。db4o甚至能追蹤到每個對象發(fā)生最后一次修改時的時間,以便用戶寫的沖突解決代碼能確定哪個對象是最近更新的。
??? 從操作行為來看,db4o的同步處理機(jī)制與原生查詢十分相似。回想一下,當(dāng)實(shí)現(xiàn)了一個原生查詢類時,我們要定義一個match方法,該方法確定哪些對象符合(或不符合)查詢規(guī)范。使用同步復(fù)制,我們要定義一個ReplicationProcess對象,我們會把沖突處理對象傳入該方法中。這些Java代碼可能像這樣:
??? . . .
??? ReplicationProcess replication = db1.ext().
??????? replicationBegin(db2, new ReplicationConflictHandler()
??????? { ?
??????????? public Object resolveConflict(
??????????????? ReplicationProcess rprocess, Object a, Object b)
??????????????? {
??????????????????? . . .? ...
??????????????????? return winning_object;
??????????????? }
??????????? )
??????? };
在上述代碼中,Object a是來自于數(shù)據(jù)庫db1的對象,Object b則來自于數(shù)據(jù)庫db2。默認(rèn)情況下,同步是雙向的。同步處理保證勝出的對象(由resolveConflict方法返回的對象)能存入這兩個數(shù)據(jù)庫中。所以當(dāng)復(fù)制完成時,這兩個數(shù)據(jù)庫中被復(fù)制的對象就同步了。
??? 最后,db4o最強(qiáng)大的特性之一就是它能毫不費(fèi)力地容忍類結(jié)構(gòu)的演變。假設(shè),在向數(shù)據(jù)庫內(nèi)加入數(shù)百個TestSuite對象之后,我們決定這個類必須要被修改。就是說,我們已經(jīng)被告之,該系統(tǒng)必須能追蹤到每個TestSuite的執(zhí)行QA工程師,所以必須加入如下字段
??? private int engineerID;
到TestSuite類的定義中。
??? 現(xiàn)在我們就遇到了兩個相關(guān)聯(lián)的問題。第一個問題不是很糟糕:已存在于數(shù)據(jù)庫中的用于表示測試的TestSuite對象,并沒有為它們記錄QA工程師的ID,所以我們將不得不將一個虛擬的值賦給這些對象的engineerID字段;該值會指出"未記錄QA工程師的ID"。第二個問題就更難應(yīng)付了:我們必須不知原因地把已有的TestSuite對象移植到"新的"類結(jié)構(gòu)中。我們必須為數(shù)據(jù)庫中所有已存在的TestSuite對象加上一個engineerID字段。除了把舊數(shù)據(jù)庫中的對象復(fù)制到一個中間性的文件,然后重新創(chuàng)建一個數(shù)據(jù)庫這種方法之外,我們還能怎么做呢?
??? 幸運(yùn)地是,使用db4o,我們確實(shí)什么都不用做。為了能操縱新的engineerID字段,以完成業(yè)務(wù)邏輯上所要求的變化,如果就只是向(我們的應(yīng)用程序中的)TestSuite類添加一個engineerID字段,我們完全不必觸動db4o API的任何調(diào)用。當(dāng)db4o使用"新的"TestSuite類結(jié)構(gòu)去讀取"舊的"TestSuite對象,db4o將認(rèn)為這些對象中的engineerID字段消失了,并且會優(yōu)雅地把該字段的值設(shè)為0。如果我們把0當(dāng)作"未記錄QA工程師的ID",那么我們所做的移植就完成了。寫入到數(shù)據(jù)庫中的新TestSuite對象將會包括新字段。(事實(shí)上,對舊的TestSuite對象本身進(jìn)行重寫,會使db4o不被察覺地為這些對象加上新字段。)所以,通過發(fā)布一個包含新的TestSuite定義的更新應(yīng)用,我們完全可以不被察覺地從舊的TestSuite對象移植到新的...正如前述應(yīng)用所做的那樣。

全方位數(shù)據(jù)庫
??? 通過適當(dāng)?shù)貞?yīng)用,db4o就能成為數(shù)據(jù)庫中的"瑞士軍刀"。它占用足夠小的內(nèi)存空間,使它能夠被包含在一個不需要消耗大量資源的項(xiàng)目中。同樣地,一個數(shù)據(jù)庫只在磁盤上占用一個文件的事實(shí)可能會使人們在第一眼看到它時,不能認(rèn)識到它豐富的功能。將數(shù)據(jù)庫從一個地方移到另一個地方就是一個簡單的文件拷貝;你不必?fù)?dān)心分離的索引文件,數(shù)據(jù)文件,數(shù)據(jù)庫結(jié)構(gòu)文件等等這些文件的位置。對于快速部署和零管理的數(shù)據(jù)庫應(yīng)用,db4o很能勝任。
??? 另外,根據(jù)我們已多次描述過的,db4o在簡單性和優(yōu)雅之間達(dá)到了適度的平衡。db4o的QBE既如此的簡單,又如此的功能強(qiáng)大,對于一組令人驚奇的應(yīng)用,它經(jīng)常是我們唯一需要的查詢API。如果你主要是通過指針導(dǎo)航而不是查詢?nèi)ピL問數(shù)據(jù)庫,QBE就特別有吸引力。在這種情況下,QBE經(jīng)常能高效地拿到一個對象網(wǎng)絡(luò)(Object Network)的根對象。然后,你就能使用db4o的激活(activation)功能從根部向下進(jìn)行對象引用導(dǎo)航,如果這些對象都完全在內(nèi)存中的話,你就更可以這么做了。
??? 而在使用QBE并不高效的時候,原生查詢和S.O.D.A.就能派上用場了,并且它們伴隨著一堆特性和低層次的API。我們還沒有展示db4o的加密功能,插入式文件I/O(例如,它允許你添加"寫后讀(read-after-write)"驗(yàn)證),信號量,客戶端/服務(wù)器端模式,以及其它難以計數(shù)的功能。我們結(jié)論性的建議很簡單:當(dāng)你的下一個Java應(yīng)用需要一個數(shù)據(jù)庫,在最終開始編碼之前,你可以去訪問一下http://www.db4objects.com/。這是很值得的。

posted on 2007-12-05 12:31 Sha Jiang 閱讀(3530) 評論(8) ?編輯 ?收藏 所屬分類: Database 、Java 、db4o 、翻譯

評論

#?re: 深入db4o(譯)2007-12-05 12:43Sha Jiang 非常歡迎大家能指正本譯文中的錯誤,謝謝!??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-05 12:46sitinspring 做個記號,有空細(xì)看.??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-06 08:32sitinspring 怎么不見DB4O的predicate式查詢?

另外DB4O沒有工具去查詢已有數(shù)據(jù)庫的對象是個遺憾.??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-06 09:05Sha Jiang > 怎么不見DB4O的predicate式查詢?
不明白何為"predicate式查詢" :-)
不過,db4o的原生查詢API中有一個類名為"Predicate",不知是否為你所期望的。
詳見"查詢方式II - 原生查詢(Native Query)"一節(jié)。

> 另外DB4O沒有工具去查詢已有數(shù)據(jù)庫的對象是個遺憾.
ObjectManager,可以到如下鏈接中下載,
http://developer.db4o.com/files/folders/objectmanager_64/default.aspx??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-06 16:46sitinspring @Sha Jiang

好,再去看看.??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-07 07:57結(jié)下梁子 我想問一下db4o目前有哪些成功項(xiàng)目???回復(fù)??更多評論
??
#?re: 深入db4o(譯)2007-12-07 08:53Sha Jiang > 我想問一下db4o目前有哪些成功項(xiàng)目?
下面的鏈接中有db4o的部分成功案例,
http://www.db4o.com/about/customers/success/??回復(fù)??更多評論
??
#?re: 深入db4o(譯)2011-07-14 09:03tom.cat @sitinspring
怎么沒人,有ECLIPSE插件??回復(fù)??更多評論

總結(jié)

以上是生活随笔為你收集整理的深入db4o的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。