應用統一的編程接口 使用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語句,所有對數據的操作和管理都可以