Berkeley DB使用簡介 1來源: 作者: 時間:2007-12-02 Tag: 點選: 587 1 簡介
BDB的全稱Berkeley DB,是一套開放源碼的嵌入式資料庫的程式庫。它為應用程式提供可伸縮的、高性能的、有事務保護功能的資料管理服務。Berkeley DB為資料的存取和管理提供了一組簡潔的函數調用API接口。
BDB為多種程式設計語言提供了API接口,其中包括C、C++、Java、Perl、Tcl、Python和PHP,所有的資料庫操作都在程式庫内部發生。多個程序,或者同一程序的多個線程可同時使用資料庫,有如各自單獨使用,底層的服務如加鎖、事務日志、共享緩沖區管理、記憶體管理等等都由程式庫透明地執行。
BDB實體結構:
2 存儲邏輯介紹
BDB所管理資料的邏輯組織機關是若幹個獨立或有一定關系的資料庫(database),每個資料庫由若幹記錄組成,這些記錄全都被表示成(key,value)的形式。
如果把一組相關的(key,value)對也看作一個表的話,那麼每一個資料庫隻允許存放一個table,這一點不同于一般的關系資料庫。實際上,在Berkeley DB中所提到的“資料庫”,相當于一般關系資料庫系統中的表;而“key/data”對相當于關系資料庫系統中的行(rows);Berkeley DB不提供關系資料庫中列直接通路的功能,而是在“key/data”對中的data項中通過實際應用來封裝字段(列)。
在實體組織上,每一個資料庫在建立的時候可以由應用程式根據其資料特點來選擇一種合适的存儲結構。可供選擇的四種檔案存儲結構分别是:哈希、B樹、定長記錄(隊列)和變長記錄(基于記錄号的簡單存儲方式)。
其中定長記錄和變長記錄存儲方法必須使用邏輯記錄号(logical record numbers,本質上就是一個整數)做為key。
哈希和B樹存儲方法對key沒有特别的要求。當資料量非常多時(記憶體不能放下所有資料時),建議使用哈希,因為哈希比B樹的索引資訊小,會少一些I/O操作。
3 系統結構介紹:
BDB由五個主要的子系統構成.包括: 存取管理子系統、記憶體池管理子系統、事務子系統、鎖子系統以及日志子系統。
3.1 資料存取子系統
資料存取(Access Methods)子系統為建立和通路資料庫檔案提供了多種支援。Berkeley DB提供了以下四種檔案存儲方法:
哈希檔案、B樹、定長記錄(隊列)和變長記錄(基于記錄号的簡單存儲方式),應用程式可以從中選擇最适合的檔案組織結構。
建立表時可以使用任意一種結構,并且可以在同一個應用程式中對不同存儲類型的檔案進行混合操作。
3.2 記憶體池管理子系統
記憶體池(Memory pool)子系統對Berkeley DB所使用的共享緩沖區進行有效的管理。它允許同時通路資料庫的多個程序或者程序的多個線程共享一個高速緩存,負責将修改後的頁寫回檔案和為新調入的頁配置設定記憶體空間。
它也可以獨立于Berkeley DB系統之外,單獨被應用程式使用,為其自己的檔案和頁配置設定記憶體空間。
記憶體池管理子系統适用于需要靈活的、面向頁的、緩沖的共享檔案通路的應用。
記憶體資料和硬碟檔案的同步有兩種方式:
1. 需要程式顯式條用同步函數才能完成,當資料量比較大時同步比較慢,會造成大量的I/O操作,而且由于内部鎖的原因,會對查詢造成影響。
2. 在BDB打開時會設定一個cache的大小,也就是BDB使用記憶體的大小。如果超過這個大小,BDB會自動同步資料到硬碟檔案。
3.3 事務子系統
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8699.html
事務(Transaction)子系統為Berkeley DB提供事務管理功能。它允許把一組對資料庫的修改看作一個原子機關,這組操作要麼全做,要麼全不做。在預設的情況下,系統将提供嚴格的ACID事務屬性,但是應用程式可以選擇不使用系統所作的隔離保證。該子系統使用兩段鎖技術和先寫日志政策來保證資料庫資料的正确性和一緻性。
它也可以被應用程式單獨使用來對其自身的資料更新進行事務保護。事務子系統适用于需要事務保證資料的修改的應用。
在本次項目裡,并沒有用到事務,是以對此研究也不夠深入。
3.4 鎖子系統
鎖(Locking)子系統為BDB提供鎖機制,為系統提供多使用者讀取和單使用者修改同一對象的共享控制。
資料存取子系統可利用該子系統獲得對頁或記錄的讀寫權限;事務子系統利用鎖機制來實作多個事務的并發控制。
該子系統也可被應用程式單獨采用。鎖子系統适用于一個靈活的、快速的、可設定的鎖管理器。
目前的使用上來看,當使用BDB的程序異常終止時,所占用的鎖并不能釋放,需要删除BDB環境檔案才能釋放所有鎖。這個問題後期再詳細研究一下。
3.5 日志子系統
日志(Logging)子系統采用的是先寫日志的政策,用于支援事務子系統進行資料恢複,保證資料一緻性。
4 編譯、安裝
可以在http://www.oracle.com/technology/products/berkeley-db/index.html 現在最新的安裝包和文檔。
将安裝包結壓後,進入build_unix目錄
../dist/configure
Make
Make install
就可以完成編譯,安裝
安裝的預設目錄是/usr/local/BerkeleyDB.4.5/,如果要安裝到其他目錄,在configure是指定--prefix=NEW_DIR即可。如果要使用BDB的c++,在configure指定--enable-cxx即可。
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8699_2.html
5 C++API介紹
經常用的類有5個
1. DbEnv:環境類,主要用于設定BDB是否需要日志、是否需要鎖等資訊;提供打開、關閉等操作
2. Db:DB類,使用者操作資料,提供打開、關閉、查找、删除、同步等操作
3. Dbt:資料類,向Db中存入、取出資料都需要使用這個類。
4. DbException及其子類:異常類
5. Dbc:遊标類,當對資料庫中多組資料進行操作時使用
#include <db_cxx.h>
#include <string>
#include <iostream>
using namespace std;
DbEnv *g_env = NULL;
Db *g_db = NULL;
void closeEnv()
{
try
{
if(g_db)
{
g_db->close(0);
delete g_db;
g_db = NULL;
}
if(g_env)
{
g_env->close(0);
delete g_env;
g_env = NULL;
}
}
catch(...)
{
}
}
int main()
{
//環境目錄,日志檔案将建立在這個目錄下
string strEnvHome = "./db/";
//建立DB|初始化日志
unsigned int nEnvFlags = DB_CREATE | DB_INIT_LOG | DB_INIT_MPOOL;
//db檔案名
string strDbFileName = get_current_dir_name();
strDbFileName += "/db/datafile";
try
{
g_env = new DbEnv(0);
g_env->set_error_stream(&std::cerr);
g_env->set_cachesize(0, 10 * 1024 * 1024, 1);
//打開環境
g_env->open(strEnvHome.c_str(), nEnvFlags, 0);
g_db = new Db(g_env, 0);
g_db->set_error_stream(&std::cerr);
//用B樹的結構打開資料庫,如果不存在則建立
g_db->open(NULL, strDbFileName.c_str(), NULL, DB_BTREE, DB_CREATE, 0);
}
catch(DbException& e)
{
cout<<"打開資料庫出錯:"<<e.what()<<endl;
closeEnv();
return -1;
}
Dbt key, data;
char sKey[1024], sData[1024];
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8698.html
//插入資料庫
try
{
for(int i=0; i<100; i++)
{
snprintf(sKey, sizeof(sKey), "key%d", i);
snprintf(sData, sizeof(sData), "data%d", i);
key.set_data(sKey);
key.set_size( strlen(sKey) );
data.set_data(sData);
data.set_size( strlen(sData) );
//put方法:當資料庫中有對應的key時,做updata操作;當沒有對應的key時,做insert操作
if( g_db->put(NULL, &key, &data, 0) != 0)
{
//插入出錯
cout<<"插入第"<<i<<"個資料時出錯"<<endl;
}
}
}
catch(DbException& e)
{
cout<<"寫入資料庫出錯:"<<e.what()<<endl;
closeEnv();
return -1;
}
//同步記憶體的資料到檔案
g_db->sync(0);
//查找資料
try
{
snprintf(sKey, sizeof(sKey), "key%d", 57);
key.set_data(sKey);
key.set_size( strlen(sKey) );
if(g_db->get(NULL, &key, &data, 0) != 0)
{
//未查找到
cout<<"未查找到,key:"<<sKey<<endl;
}
else
{
//查找到
memcpy(sData, data.get_data(), data.get_size() );
sData[data.get_size()] = '/0';
cout<<"key:"<<sKey<<";data:"<<sData<<endl;
}
}
catch(DbException& e)
{
cout<<"查找資料庫出錯:"<<e.what()<<endl;
closeEnv();
return -1;
}
//用遊标周遊
try
{
Dbc *cursorp;
if( g_db->cursor(NULL, &cursorp, 0) != 0)
{
cout<<"[get cursor 錯誤."<<endl;
}
else
{
while (cursorp->get(&key, &data, DB_NEXT) == 0)
{
memcpy(sKey, key.get_data(), key.get_size() );
sKey[key.get_size()] = '/0';
memcpy(sData, data.get_data(), data.get_size() );
sData[data.get_size()] = '/0';
cout<<"key:"<<sKey<<";data:"<<sData<<endl;
}
}
}
catch(DbException& e)
{
cout<<"用遊标周遊出錯:"<<e.what()<<endl;
closeEnv();
return -1;
}
closeEnv();
}
本文來自: (www.91linux.com) 詳細出處參考:http://www.91linux.com/html/article/database/20071202/8698_2.html