• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 3  文章 - 2  trackbacks - 0
            <2011年3月>
            272812345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            文章分類

            文章檔案

            相冊

            ACE資料

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜


            [轉載]開源嵌入式數據庫Berkeley DB
            開源嵌入式數據庫Berkeley DB
            作者:肖文鵬 發文時間:2004.04.09

            像MySQL這類基于C/S結構的關系型數據庫系統雖然代表著目前數據庫應用的主流,但卻并不能滿足所有應用場合的需要。有時我們需要的可能只是一個簡單的基于磁盤文件的數據庫系統。這樣不僅可以避免安裝龐大的數據庫服務器,而且還可以簡化數據庫應用程序的設計。Berkeley DB正是基于這樣的思想提出來的。

            Berkeley DB簡介

            Berkeley DB是一個開放源代碼的內嵌式數據庫管理系統,能夠為應用程序提供高性能的數據管理服務。應用它程序員只需要調用一些簡單的API就可以完成對數據的訪問和管理。與常用的數據庫管理系統(如MySQL和Oracle等)有所不同,在Berkeley DB中并沒有數據庫服務器的概念。應用程序不需要事先同數據庫服務建立起網絡連接,而是通過內嵌在程序中的Berkeley DB函數庫來完成對數據的保存、查詢、修改和刪除等操作。

            Berkeley DB為許多編程語言提供了實用的API接口,包括C、C++、Java、Perl、Tcl、Python和PHP等。所有同數據庫相關的操作都由Berkeley DB函數庫負責統一完成。這樣無論是系統中的多個進程,或者是相同進程中的多個線程,都可以在同一時間調用訪問數據庫的函數。而底層的數據加鎖、事務日志和存儲管理等都在Berkeley DB函數庫中實現。它們對應用程序來講是完全透明的。俗話說:“麻雀雖小五臟俱全?!盉erkeley DB函數庫本身雖然只有300KB左右,但卻能夠用來管理多達256TB的數據,并且在許多方面的性能還能夠同商業級的數據庫系統相抗衡。就拿對數據的并發操作來說,Berkeley DB能夠很輕松地應付幾千個用戶同時訪問同一個數據庫的情況。此外,如果想在資源受限的嵌入式系統上進行數據庫管理,Berkeley DB可能就是惟一正確的選擇了。

            Berkeley DB作為一種嵌入式數據庫系統在許多方面有著獨特的優勢。首先,由于其應用程序和數據庫管理系統運行在相同的進程空間當中,進行數據操作時可以避免繁瑣的進程間通信,因此耗費在通信上的開銷自然也就降低到了極低程度。其次,Berkeley DB使用簡單的函數調用接口來完成所有的數據庫操作,而不是在數據庫系統中經常用到的SQL語言。這樣就避免了對結構化查詢語言進行解析和處理所需的開銷。

            基本概念

            Berkeley DB簡化了數據庫的操作模式,同時引入了一些新的基本概念,從而使得訪問和管理數據庫變得相對簡單起來。在使用Berkeley DB提供的函數庫編寫數據庫應用程序之前,有必要先了解以下這些基本概念。

            關鍵字和數據

            關鍵字(Key)和數據(Data)是Berkeley DB用來進行數據庫管理的基礎,由這兩者構成的Key/Data對(見表1)組成了數據庫中的一個基本結構單元,而整個數據庫實際上就是由許多這樣的結構單元所構成的。通過使用這種方式,開發人員在使用Berkeley DB提供的API來訪問數據庫時,只需提供關鍵字就能夠訪問到相應的數據。

            Key Data?
            sport football
            Fruit orange
            Drink beer


            表1 Key/Data對

            如果想將第一行中的“sport”和“football”保存到Berkeley DB數據庫中,可以調用Berkeley DB函數庫提供的數據保存接口。此時“sport”和“football”將分別當成關鍵字和數據來看待。之后如果需要從數據庫中檢索出該數據,可以用“sport”作為關鍵字進行查詢。此時Berkeley DB提供的接口函數會返回與之對應的數據“football”。

            關鍵字和數據在Berkeley DB中都是用一個名為DBT的簡單結構來表示的。實際上兩者都可以是任意長度的二進制數據,而DBT的作用主要是保存相應的內存地址及其長度,其結構如下所示:

            typedef struct {
            ? void *data;
            ? u_int32_t size;
            ? u_int32_t ulen;
            ? u_int32_t dlen;
            ? u_int32_t doff;
            ? u_int32_t flags;
            } DBT;

            ?

            在使用Berkeley DB進行數據管理時,缺省情況下是一個關鍵字對應于一個數據,但事實上也可以將數據庫配置成一個關鍵字對應于多個數據。

            對象句柄

            在Berkeley DB函數庫定義的大多數函數都遵循同樣的調用原則:首先創建某個結構,然后再調用該結構中的某些方法。從程序設計的角度來講,這一點同面向對象的設計原則是非常類似的,即先創建某個對象的一個實例,然后再調用該實例的某些方法。正因如此,Berkeley DB引入了對象句柄的概念來表示實例化后的結構,并且將結構中的成員函數稱為該句柄的方法。

            對象句柄的引入使得程序員能夠完全憑借面向對象的思想,來完成對Berkeley DB數據庫的訪問和操作,即使當前使用的是像C這樣的結構化語言。例如,對于打開數據庫的操作來說,可以調用DB的對象句柄所提供的open函數,其原型如下所示:

            int DB->open(DB *db, DB_TXN *txnid, const char *file,
            const char *database, DBTYPE type, u_int32_t flags, int mode);

            ?

            錯誤處理

            對于任何一個函數庫來說,如何對錯誤進行統一的處理都是需要考慮的問題。Berkeley DB提供的所有函數都遵循同樣的錯誤處理原則,即函數成功執行后返回零,否則的話則返回非零值。

            對于系統錯誤(如磁盤空間不足和訪問權限不夠等),返回的是一個標準的值;而對于非系統錯誤,返回的則是一個特定的錯誤編碼。例如,如果在數據庫中沒有與某個特定關鍵字所對應的數據,那么在通過該關鍵字檢索數據時就會出現錯誤。此時函數的返回值將是DB_NOTFOUND,表示所請求的關鍵字并沒有在數據庫中出現。所有標準的errno值都是大于零的,而由Berkeley DB定義的特殊錯誤編碼則都是小于零的。

            要求程序員記住所有的錯誤代號既不現實也沒有什么實際意義,因為Berkeley DB提供了相應的函數來獲得錯誤代號所對應的錯誤描述。一旦有錯誤發生,只需首先調用db_strerror()函數來獲得錯誤描述信息,然后再調用DB->err()或DB->errx()就可以很輕松地輸出格式化后的錯誤信息。? 開源嵌入式數據庫Berkeley DB(2)?
            作者:肖文鵬 發文時間:2004.04.09

            接上一篇:開源的嵌入式數據庫Berkeley DB(1)

            ?

            應用統一的編程接口

            使用Berkeley DB提供的函數來進行數據庫的訪問和管理并不復雜,在大多數場合下只需按照統一的接口標準進行調用就可以完成最基本的操作。

            打開數據庫

            打開數據庫通常要分兩步進行:首先調用db_create()函數來創建DB結構的一個實例,然后再調用DB->open()函數來完成真正的打開操作。Berkeley DB將所有對數據庫的操作都封裝在名為DB的結構中。db_create()函數的作用就是創建一個該結構,其原型如下所示:

            typedef struct__db DB;
            int db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags);

            ?

            將磁盤上保存的文件作為數據庫打開是由DB->open()函數來完成的,其原型如下所示:

            int DB->open(DB *db, DB_TXN *txnid, const char *file,
            const char *database, DBTYPE type, u_int32_t flags, int mode);

            ?

            下面這段代碼示范了如何創建DB對象句柄及如何打開數據庫文件:

            #include <sys/types.h>
            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #include <db.h>
            #define DATABASE "demo.db"
            /* 以下程序代碼的程序頭同此*/
            int main()
            { DB *dbp;
            int ret;
            if ((ret = db_create(&dbp, NULL, 0)) != 0) {
            ? fprintf(stderr, "db_create: %s\n", db_strerror(ret));
            ? exit (1);
            }
            if ((ret = dbp->open(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
            ? dbp->err(dbp, ret, "%s", DATABASE);
            ? exit (1);
            }
            }

            ?

            代碼首先調用db_create()函數來創建一個DB對象句柄。變量dbp在調用成功后將成為數據庫句柄,通過它可以完成對底層數據庫的配置或訪問。接下去調用DB->open()函數打開數據庫文件,參數“DATABASE”指明對應的磁盤文件名為demo.db;參數“DB_BTREE”表示數據庫底層使用的數據結構是B樹;而參數“DB_CREATE”和“0664”則表明當數據庫文件不存在時創建一個新的數據庫文件,并且將該文件的屬性值設置為0664。

            錯誤處理是在打開數據庫時必須的例行檢查,這可以通過調用DB->err()函數來完成。其中參數“ret”是在調用Berkeley DB函數后返回的錯誤代碼,其余參數則用于顯示結構化的錯誤信息。

            添加數據

            向Berkeley DB數據庫中添加數據可以通過調用DB->put()函數來完成,其原型如下所示:

            int DB->put(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags);

            ?

            下面這段代碼示范了如何向數據庫中添加新的數據:

            int main()
            { DB *dbp;
            DBT key, data;
            int ret;
            if ((ret = db_create(&dbp, NULL, 0)) != 0) {
            ? fprintf(stderr, "db_create: %s\n", db_strerror(ret));
            ? exit (1);
            }
            if ((ret = dbp->open(dbp,
            ? NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
            ? dbp->err(dbp, ret, "%s", DATABASE);
            ? exit (1);
            }
            memset(&key, 0, sizeof(key));
            memset(&data, 0, sizeof(data));
            key.data = "sport";
            key.size = sizeof("sport");
            data.data = "football";
            data.size = sizeof("football");
            if ((ret = dbp->put(dbp, NULL, &key, &data, 0)) == 0)
            ? printf("db: %s: key stored.\n", (char *)key.data);
            else
            ? dbp->err(dbp, ret, "DB->put");
            }

            ?

            代碼首先聲明了兩個DBT結構變量,并分別用字符串“sport”和“football”進行填充。它們隨后作為關鍵字和數據傳遞給用來添加數據的DB->put()函數。DBT結構幾乎會在所有同數據訪問相關的函數中被用到。

            在向數據庫中添加數據時,如果給定的關鍵字已經存在,大多數應用會對于已經存在的數據采用覆蓋原則。也就是說,如果數據庫中已經保存了一個“sport/basketball”對,再次調用DB->put()函數添加一個“sport/football”對,那么先前保存的那些數據將會被覆蓋。但Berkeley DB允許在調用DB->put()函數時指定參數“DB_NOOVERWRITE”,聲明不對數據庫中已經存在的數據進行覆蓋,其代碼如下:

            if ((ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) == 0)
            printf("db: %s: key stored.\n", (char *)key.data);
            else
            dbp->err(dbp, ret, "DB->put");

            ?

            一旦給出“DB_NOOVERWRITE”標記,如果DB->put()函數在執行過程中發現給出的關鍵字在數據庫中已經存在了,就無法成功地把該Key/Data對添加到數據庫中,于是將返回錯誤代號“DB_KEYEXIST”。

            檢索數據

            從Berkeley DB數據庫中檢索數據可以通過調用DB->get()函數來完成,其原型如下所示:

            int DB->get(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags);

            ?

            下面這段代碼示范了如何從數據庫中檢索出所需的數據:

            int main()
            { DB *dbp;
            DBT key, data;
            int ret;
            if ((ret = db_create(&dbp, NULL, 0)) != 0) {
            ? fprintf(stderr, "db_create: %s\n", db_strerror(ret));
            ? exit (1);
            }
            if ((ret = dbp->open(dbp,
            ? NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
            ? dbp->err(dbp, ret, "%s", DATABASE);
            ? exit (1);
            }
            memset(&key, 0, sizeof(key));
            memset(&data, 0, sizeof(data));
            key.data = "sport";
            key.size = sizeof("sport");
            if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0)
            ? printf("db: %s: key retrieved: data was %s.\n",
            ?? (char *)key.data, (char *)data.data);
            else
            ? dbp->err(dbp, ret, "DB->get");
            }

            ?

            代碼同樣聲明了兩個DBT結構變量,并且調用memset()函數對它們的內容清空。雖然Berkeley DB并不強制要求在進行數據操作之前先清空它們,但出于提高代碼質量考慮還是建議先進行清空操作。在進行數據檢索時,對DB->get()函數的返回值進行處理是必不可少的,因為它攜帶著檢索操作是否成功完成等信息。下面列出的是DB->get()函數的返回值:

            ◆ 0 函數調用成功,指定的關鍵字被找到;

            ◆ DB_NOTFOUND 函數調用成功,但指定的關鍵字未被找到;

            ◆大于0 函數調用失敗,可能出現了系統錯誤。

            刪除數據

            從Berkeley DB數據庫中刪除數據可以通過調用DB->del()函數來完成,其原型如下所示:

            int DB->del(DB *db, DB_TXN *txnid, DBT *key, u_int32_t flags);

            ?

            下面這段代碼示范了如何從數據庫中刪除數據:

            int main()
            { DB *dbp;
            DBT key;
            int ret;
            if ((ret = db_create(&dbp, NULL, 0)) != 0) {
            ? fprintf(stderr, "db_create: %s\n", db_strerror(ret));
            ? exit (1);
            }
            if ((ret = dbp->open(dbp,
            ? NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
            ? dbp->err(dbp, ret, "%s", DATABASE);
            ? exit (1);
            }
            memset(&key, 0, sizeof(key));
            key.data = "sport";
            key.size = sizeof("sport");
            if ((ret = dbp->del(dbp, NULL, &key, 0)) == 0)
            ? printf("db: %s: key was deleted.\n", (char *)key.data);
            else
            ? dbp->err(dbp, ret, "DB->del");
            }

            ?

            刪除數據只需給出相應的關鍵字,不用指明與之對應的數據。

            關閉數據庫

            對于一次完整的數據庫操作過程來說,關閉數據庫是不可或缺的一個環節。這是因為Berkeley DB需要依賴于系統底層的緩沖機制,也就是說只有在數據庫正常關閉的時候,修改后的數據才有可能全部寫到磁盤上,同時它所占用的資源也才能真正被全部釋放。關閉數據庫的操作是通過調用DB->close()函數來完成的,其原型如下所示:

            int DB->close(DB *db, u_int32_t flags);

            ?

            下面這段代碼示范了如何在需要的時候關閉數據庫:

            int main()
            { DB *dbp;
            DBT key, data;
            int ret, t_ret;
            if ((ret = db_create(&dbp, NULL, 0)) != 0) {
            ? fprintf(stderr, "db_create: %s\n", db_strerror(ret));
            ? exit (1);
            }
            if ((ret = dbp->open(dbp,
            ? NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
            ? dbp->err(dbp, ret, "%s", DATABASE);
            ? goto err;
            }
            memset(&key, 0, sizeof(key));
            memset(&data, 0, sizeof(data));
            key.data = "sport";
            key.size = sizeof("sport");
            if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0)
            ? printf("db: %s: key retrieved: data was %s.\n",
            ?? (char *)key.data, (char *)data.data);
            else
            ? dbp->err(dbp, ret, "DB->get");
            if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
            ? ret = t_ret;
            exit(ret);
            }

            ?

            小結

            Berkeley DB這個嵌入式數據庫系統使用非常簡單。它沒有數據庫服務器的概念,也不需要復雜的SQL語句,所有對數據的操作和管理都可以通過函數調用來完成,非常適合于那些需要對數據進行簡單管理的應用場合。

            ?

            ?

            posted on 2006-12-14 10:22 Sword.Hell blog 閱讀(353) 評論(0)  編輯 收藏 引用 所屬分類: 使用Berkeley DB
            中文字幕久久欲求不满| 久久综合综合久久综合| 色综合久久久久久久久五月| 久久综合亚洲色HEZYO国产| 精品久久久久久综合日本| 狠狠色婷婷综合天天久久丁香| 无码人妻精品一区二区三区久久久 | 久久男人AV资源网站| A级毛片无码久久精品免费| 韩国三级中文字幕hd久久精品 | 狠色狠色狠狠色综合久久| 久久精品国产精品青草app| 国产精久久一区二区三区| 久久国产成人亚洲精品影院| 婷婷久久综合九色综合绿巨人| 久久这里有精品| 久久影院综合精品| 99久久亚洲综合精品网站| 久久久久免费视频| 热99RE久久精品这里都是精品免费| 亚洲国产精品无码久久久秋霞2| 狠狠狠色丁香婷婷综合久久五月 | 亚洲级αV无码毛片久久精品| 久久精品人人做人人爽电影蜜月 | 久久精品二区| 中文字幕乱码久久午夜| 一本大道加勒比久久综合| 久久久久久青草大香综合精品| 亚洲日本va中文字幕久久| 日本道色综合久久影院| 区久久AAA片69亚洲| 国产福利电影一区二区三区久久老子无码午夜伦不 | 精品久久久无码中文字幕| 无码8090精品久久一区| 久久精品人人槡人妻人人玩AV| 久久强奷乱码老熟女| 久久国产色AV免费观看| 亚洲精品成人久久久| 久久精品国产亚洲沈樵| 亚洲国产精品无码久久98| 久久综合九色综合欧美就去吻|