<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    John Jiang

    a cup of Java, cheers!
    https://github.com/johnshajiang/blog

       :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
      131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
    深入db4o
        這是Rick Grehan發表在TheServerSide上的一篇關于面向對象數據庫--db4o的文章,較全面地介紹了db4o的關鍵特性,希望對大家認識db4o能有所幫助。(2007.12.07最后更新)

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

    db4o基礎
        讓我們以初學者使用db4o時可能會做的事情開始:定義了一些類,然后持久化這些類的對象。我們所假定的類為同樣也是假定的QA項目做一個跟蹤測試的系統。我們的系統由兩個類組成,首先是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對象的容器,(一個測試用例就是一個可單獨執行的測試程序--相關的測試用例組合成一個測試組)。測試組使用額外的,全局的數據成員,每個數據成員的用途也是相對明顯的:configuration記錄被測試的指定系統;overallScore是對整個測試組一個簡要的評分('P'代表通過,'F'代表失敗,'B'代表被阻塞,等等。);dateExec是一個毫秒級的域,標識該測試組被執行時的日期與時刻。是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> ...
        }
        每個測試用例都有一個名稱,形式自由的注釋字段,狀態(通過或失敗),持續時間和結果(例如,為了與測試-字節/秒的吞吐量-的任意數據關聯)。
        因為我們所關注是db4o的使用,所以我們不想在描述這些類的使用細節上停留。就讓我們簡單地說,我們已經執行了一個特別地測試組中所有的測試用例,將測試的結果存放在一個TestSuite對象中(與TestCase對象相關的ArrayList對象cases中),然后關閉數據庫。是不是太容易了。
        // 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();
        就是它。彈指一揮間,你就已經做到了。(當然,為了保持簡潔,我們去掉了創建TestSuite對象和它的TestCase組件的細節)
        停下來想想上述代碼做了什么事情。特別要考慮你沒有看到的--db4o已經做了但還未被告之的事情。
        首先,我們不需要告訴db4o任何關于TestSuite類的結構的信息;不需要我們的幫助,db4o就能發現這個結構。利用Java反射機制的能力,db4o測定TestSuite類的結構,并勾勒出該類的裝配方式以推導出此類對象的成員與關鍵數據。
        第二,我們不必建議db4o去關注ArrayList。不僅我們不必將ArrayList的大小告訴db4o,而且我們也不必把它里面的內容告訴db4o。正如db4o在它剛接觸testsuite對象時就能夠發現它所需要的一切,db4o也能知道它所需要的關于(在ArrayList中的)TestCase對象的所有信息。
        結果就是,如果我們把testsuite作為一個任意寵大而復雜的對象樹的根,db4o能找到并存儲整個樹而不需要我們的任何協助。所以,存儲這個處于根部的對象testsuite也就是存儲了整個ArrayList對象。
        最后,我們也沒有必須要求db4o以事務的保護性方式去調用set方法。任何會修改ObjectContainer(表示數據庫的db4o對象)的調用都會自動地開啟一個事務,除非已經有一個活躍的事務了。此外還會調用close方法去終止這個事務,所以上述代碼等價于:
        db.startTransaction();
        db.set(testsuite);
        db.commitTransaction();
        db.close();
        此處的startTransaction和commitTransaction方法是為了證明我們的觀點而虛構的。db4o也確實有顯示地提交或中止事務的方法,但為了使原先的代碼足夠的簡潔我們沒有使用這些方法。db4o隱式的事務使得數據庫能夠一直處于一致的狀態;一旦commit方法已經執行了,數據庫的完整性就能夠得到保證,甚至是發生了災難性失敗也能如此。

    查詢I - QBE
        有了已經存于數據庫中的對象,下一步我們想要展示的操作將肯定就是查詢和恢復。db4o提供了三種查詢API:有一種簡單,有一種優雅,還有一種則復雜。每一種API都有其所長,并適用于不同的查詢條件。以db4o的眼光來看,你選擇哪一種API并沒有關系:它們都是可兼容的。
        我們以簡單的API開始:query by exampel(QBE)。
        使用QBE是如此的容易:為你的查詢目標構建一個'模板'對象,然后把它傳入ObjectContainer的query方法。實際上,你就是告訴db4o'去拿到所有與這個對象看起來一樣的對象'。(這與JavaSpaces查詢API非常相似;為了清楚地了解如何處理基本數據類型,可以看下面的內容,db4o的處理方式與JavaSpaces不同。也要注意,JavaSpace Entry對象期望使用public字段,db4o則沒有這種要求。)
        假設一個測試組名為"Network Throughput",我們想取出這個測試組執行的所有測試以便我們能確定失敗了的測試所占的百分比(基于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字段有真實的值;所有其它的成員變量不是為null就是為0。Null或0字段不參與QBE查詢;因此,調用db.get方法就會返回在該數據庫中name字段匹配"Network Throughput"的所有TestSuite對象。匹配的TestSuite對象將返回在一個ObjectSet結果對象中。上述代碼遍歷該結果,取出對象,然后計算結果并展示出來。
        QBE明顯的優點就是它的簡易性。不需要掌握其它單獨的查詢語言。另外,QBE也是類型安全的:你不需要創建一個類似于SQL的查詢語句
        SELECT TestSuite.overallScore FROM TestSuite WHERE TestSuite.name = 200.0
        另一方面,由于該查詢是由Java代碼創建的,編譯器不會允許你把一個浮點值賦給一個String字段;反之亦然。
        QBE明顯的缺點就是它只能執行"等于"查詢。另外,QBE使用null值去確定不參與查詢的String或對象引用成員變量,使用0值去指定不參與查詢的數字字段。所以,例如,我不能發明一個QBE查詢去獲得所有result字段的值為0的TestCase對象。
        更為精細的查詢要求一個能力更強的查詢機制,而db4o恰恰就有這樣一種機制。

    查詢方式II - 原生查詢(Native Query)
        db4o的原生查詢系統應該是能想像得到的最具彈性的查詢機制。不像使用數據庫查詢語言去構建查詢,你是使用"無格式的普通Java語句"去構造原生查詢。原生查詢用兩種手段去實現這件不可思意的工作:一個是Predicate類;另一個是QueryComparator接口。這個類包含一個可重載的(overrideable)回調方法,該方法將指定如何從數據庫中選擇對象(如果你愿意,你將會看到查詢語句的主體....)。這個接口只聲明了一個方法,該方法用于指明如何對查詢結果進行排序。
        作為一個例子,我們假設想找到在給定的一周內執行過了的總得分為"failed",但與之關聯的測試用例中有超過一半的被評為"passed"的測試組。這不是一個簡單的"等于"查詢,所以它不能使用QBE構建。
        然而,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;

            // 構造器要在本地獲得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是否在指定的日期范圍內
                if(testsuite.getDateExec()<startdate ||
                  testsuite.getDateExec()>enddate) return false;

                // 如果該測試組對象中沒有測試用例對象,則拒絕將該測試組對象放入查詢結果中
                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對象。當查詢執行時,TestSuite對象就會傳入match方法(我們之前提到過的回調方法),如果傳入的TestSuite對象符合查詢規范該方法就返回true,否則就返回false。
        match方法中的代碼首先確定侯選對象是否是在一周的日期范圍內。如果是,則循環該對象中的成員變量測試用例的對象,計算出所有通過了的測試用例的總數。如果,得到的通過率小于50%,該測試組就被拒絕;否則,就讓它通過。
        我們可以使用如下的代碼準確地展示該查詢程序:
        . . .
        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();
        . . .
        可以把原生查詢想像成這樣:目標類的對象一個接一個從數據庫中取出,然后把它們傳入match方法中。只有那些被match方法返回true的對象才會置于查詢結果ObjectSet對象中?;旧峡梢哉f,如果你會知道如何寫Java代碼,那么你就知道如何寫原生查詢。
        那么排序呢?如果想按日期的升序排列查詢結果,我們就要實現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的值。為了準確地說明對查詢結果的排序,我們實例化NativeQuerySort,并把對query方法的調用修改成如下:
        . . .
        // Instantiate the sort class
        nqsClass = new NativeQuerySort();
        . . .
        ObjectSet results = db.query(nqqClass, nqsClass);
        . . .
    其它的代碼仍然與原先的保持一致。
        好懷疑的讀者可能會抱怨道,原生查詢只是一種編程上的小伎倆--相比較于直接去拿到所有的TestSuite對象然后再排除其中不符合條件的對象這樣的程序,原生查詢并不快。
        是的,但并不十分準確。原生能夠被優化。你所需要做的只是把兩個jar文件--db4o-xxx-nqopt.jar(xxx表示db4o的版本)和bloat.jar--置于CLASSPATH環境變量中。在查詢執行的時候,這些類庫中的代碼會對(在match方法中)例如基本數據類型比較,算術和布爾表達式,簡單的對象成員訪問,以及更多方面的結構進行優化。這個被支持的優化的列表在不停的增長,因為db4o引擎還在擴展優化的范圍。

    查詢方式III - S.O.D.A.
        db4o獨一無二的能力之一就是它的API被分層了。開發者能夠選擇通過高層次--賦予數據庫引擎相當大的自由度,讓它決定如何去實現它的操作--或者開發者也可以使用一種更直接地方式去訪問db4o。后一種選擇為程序員平添了更多的負擔,程序員必須更加小心地引導數據庫引擎的內部工作。但回報就是得到一個更快,能力更強的數據庫應用。
        db4o的S.O.D.A.(Simple Object Data Access)查詢機制就是該層次API的一個完美的例子。S.O.D.A.就是db4o的內部查詢系統--QBE和原生查詢都被翻譯成了S.O.D.A.。然而,應用程序也能直接地調用S.O.D.A.。
        假設我們想找到所有名為"Network Throughput",且至少擁有一個其result字段--我們使用這個參數作為字節/秒的量度--不小于指定值(比方說,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所示圖表的幫助下,這些有點兒神秘的代碼就變得不那么神秘了。該程序所構建的歸總起來就是一個用于指導底層數據庫引擎的查詢圖(Query Graph)。descend方法創建了該圖的一個分支,該分支向下步入對象的結構中。每個descend方法就在這個樹中構建一個結點,可以在這些結點上再附上一個約束(使用constrain方法)。用SQL的話來說,約束指定了查詢的"WHERE"子句部分。多個約束可以在與(and)或或(or)方法的協助下結合起來。在上面的查詢中我們已經使用了and方法去關聯這些約束。
                                        
    與其它的查詢方式一樣,查詢結果返回到ObjectSet對象中,通過遍歷該對象就可取出那些拿到的對象。
        注意,由于S.O.D.A.是一種低層次的訪問方法,沒有智能的指示,它就沒有默認的行為。訪問cases對象的成員變量result字段的代碼很簡單
        query.descend("cases").descend("result"). ...
    我們并沒有告訴S.O.D.A."cases"是一個集合對象。所以當查詢執行時,它會不被察覺地檢測ArrayList對象cases中所有元素(TestCase對象)的result字段,然后會正確地返回那些擁有符合搜索規范的測試用例的測試組。

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

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

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

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

    評論

    # re: 深入db4o(譯) 2007-12-05 12:43 Sha Jiang
    非常歡迎大家能指正本譯文中的錯誤,謝謝!  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-05 12:46 sitinspring
    做個記號,有空細看.  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-06 08:32 sitinspring
    怎么不見DB4O的predicate式查詢?

    另外DB4O沒有工具去查詢已有數據庫的對象是個遺憾.  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-06 09:05 Sha Jiang
    > 怎么不見DB4O的predicate式查詢?
    不明白何為"predicate式查詢" :-)
    不過,db4o的原生查詢API中有一個類名為"Predicate",不知是否為你所期望的。
    詳見"查詢方式II - 原生查詢(Native Query)"一節。

    > 另外DB4O沒有工具去查詢已有數據庫的對象是個遺憾.
    ObjectManager,可以到如下鏈接中下載,
    http://developer.db4o.com/files/folders/objectmanager_64/default.aspx  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-06 16:46 sitinspring
    @Sha Jiang

    好,再去看看.  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-07 07:57 結下梁子
    我想問一下db4o目前有哪些成功項目?  回復  更多評論
      

    # re: 深入db4o(譯) 2007-12-07 08:53 Sha Jiang
    > 我想問一下db4o目前有哪些成功項目?
    下面的鏈接中有db4o的部分成功案例,
    http://www.db4o.com/about/customers/success/  回復  更多評論
      

    # re: 深入db4o(譯) 2011-07-14 09:03 tom.cat
    @sitinspring
    怎么沒人,有ECLIPSE插件  回復  更多評論
      

    主站蜘蛛池模板: 免费国产作爱视频网站| 国产精品免费视频观看拍拍| 久久99热精品免费观看动漫| 亚洲愉拍99热成人精品热久久| 美女被羞羞网站免费下载| 国产精品嫩草影院免费| 亚洲av纯肉无码精品动漫| 日韩一区二区三区免费体验| 亚洲精品国产综合久久久久紧| 两个人的视频高清在线观看免费| 亚洲国产片在线观看| 最近最新的免费中文字幕| 亚洲 欧洲 视频 伦小说| 成人毛片18岁女人毛片免费看| 精品亚洲456在线播放| 毛片免费观看的视频在线| 亚洲成_人网站图片| 日本特黄特色免费大片| 美女隐私免费视频看| 亚洲毛片不卡av在线播放一区| 一区二区视频免费观看| 久久久青草青青亚洲国产免观| 久久国产精品国产自线拍免费| 日韩亚洲Av人人夜夜澡人人爽| 7x7x7x免费在线观看| 香蕉大伊亚洲人在线观看| www亚洲精品少妇裸乳一区二区| 春意影院午夜爽爽爽免费| 亚洲色爱图小说专区| 99国产精品永久免费视频| 亚洲a无码综合a国产av中文| 亚洲乱码中文字幕手机在线| 桃子视频在线观看高清免费视频 | 18禁网站免费无遮挡无码中文 | 免费精品国自产拍在线播放 | 一本色道久久88—综合亚洲精品 | 亚洲免费二区三区| 国产精品亚洲专区无码不卡| 亚洲色婷婷综合久久| 亚洲精品国产免费| 豆国产96在线|亚洲|