Berkeley DB——Records
Berkeley DB——Records
?
本文主要講述如何操作Berkeley DB的記錄——Records的Create、Retrieve、Update和Delete。
Key/Data Pair and Dbt object
Berkeley DB中保存的是key/data對,它們都是Dbt對象:
| #include <db_cxx.h> ? class Dbt { public: ?????? Dbt(void *data, size_t size); ?????? Dbt(); ?????? Dbt(const Dbt &); ?????? Dbt &operator = (const Dbt &); ?????? ~Dbt(); ? ?????? void *get_data() const; ?????? void set_data(void *); ? ?????? u_int32_t get_size() const; ?????? void set_size(u_int32_t); ? ?????? u_int32_t get_ulen() const; ?????? void set_ulen(u_int32_t); ? ?????? u_int32_t get_dlen() const; ?????? void set_dlen(u_int32_t); ? ?????? u_int32_t get_doff() const; ?????? void set_doff(u_int32_t); ? ?????? u_int32_t get_flags() const; ?????? void set_flags(u_int32_t); ? ?????? DBT *Dbt::get_DBT(); ?????? const DBT *Dbt::get_const_DBT() const; ?????? static Dbt *Dbt::get_Dbt(DBT *dbt); ?????? static const Dbt *Dbt::get_const_Dbt(const DBT *dbt); }; ? |
它是DBT對象的c++封裝,而DBT是一個結構體。如果我們設置DB的訪問方法為B樹或者Hash的話,Key可以為任何值。而如果我們定義一個有n-1(相對于有n個字段的關系數據庫表)個字段的struct,將類型為這個struct的對象存入數據庫的話,就相當于我們存入了n個字段的值了,只是我們不能以data中的字段作為查詢條件,而只能以key為查詢條件。
Writing Records to the DB
通常情況下,我們需要設置Dbt對象的data和len,以指明需要保存的數據和數據所占用空間的大小——不是指針的大小而是實際數據所占空間的大小。當寫數據到DB中的時候,我們需要設置key/data對的size和data。存入的數據最好是那些c/c++的基本數據類型——比如我們想存入字符串,那應該使用char*或者wchar_t*類型,而不是string或者wstring。根據我的實踐,如果存入string和wstring會發生一些奇怪的問題,具體看這里。
如果數據庫不允許重復記錄的話(默認情況,如果想存入重復記錄需要對Db設置相應的flag),put方法就相當于關系數據庫中的insert or update:
int Db::put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
我們可以給put方法傳入不同的flag來控制put的具體行為,這些flag有:
| Flag(Db.put) | Description |
| 0 | 添加數據到數據庫中。如果DB不允許重復記錄,當已經有相同的key的記錄時,將修改原記錄,否則存入新記錄;如果DB允許重復,則添加新記錄。 |
| DB_APPEND | 只針對Queue和Recno的DB,將記錄添加到數據庫的末尾 |
| DB_NODUPDATA | 只針對B樹和Hash的DB,且數據庫需要設置為允許重復記錄,如果不存在相同key的記錄,則存入新記錄,否則返回DB_KEYEXIST |
| DB_NOOVERWRITE | 當不存在key相同的記錄時,存入新的記錄,而不管DB是否允許有重復記錄;否則返回DB_KEYEXIST |
?
代碼示例:
| #include <db_cxx.h> #include <string.h> ? ... ? char *description = "Grocery bill."; float money = 122.45; ? Db my_database(NULL, 0); // Database open omitted for clarity ? Dbt key(&money, sizeof(float)); Dbt data(description, strlen(description) + 1); ? int ret = my_database.put(NULL, &key, &data, DB_NOOVERWRITE); if (ret == DB_KEYEXIST) { ??? my_database.err(ret, "Put failed because key %f already exists", money); } |
?
Getting Records from the DB
可以使用get方法從DB中根據key來獲取數據:
int Db::get(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);
必須先設定key的值和size,把data當作out參數傳入,如果搜索到記錄,則數據會寫入data參數中,并且get方法返回0,否則返回非零值,這些返回值的含義如下:
| Result | Description |
| 0 | 成功 |
| -30989 | 沒有找到此key的記錄 |
?
get方法也有一個flag參數,常用的flag有:
| Flag | Description |
| 0 | 取出key匹配的一條記錄,填充data參數 |
| DB_GET_BOTH | 當key和data都匹配時,填充data參數 |
| DB_SET_RECNO | 根據行號來搜索記錄,key和data參數都將被填充(僅針對B+樹的DB)。 |
| DB_MULTIPLE | 當key匹配時,返回一批數據到data參數所指的buffer中(針對設置了允許重復記錄的DB) |
?
一個例子:
| #include <db_cxx.h> #include <string.h> ... ? float money; char *description; ? Db my_database(NULL, 0); // Database open omitted for clarity ? money = 122.45; ? Dbt key, data; // Use our own memory to retrieve the float. // For data alignment purposes. key.set_data(&money); key.set_ulen(sizeof(float)); key.set_flags(DB_DBT_USERMEM); ? my_database.get(NULL, &key, &data, 0); ? // Money is set into the memory that we supplied. description = (char *)data.get_data(); |
?
Deleting Records
刪除記錄使用del方法:
int Db::del(DbTxn *txnid, Dbt *key, u_int32_t flags);
如果DB設置為允許重復記錄的話,那key匹配的所有記錄都被刪除。想一條條記錄刪除的話,需要使用游標。
一個例子:
| #include <db_cxx.h> ? ... ? Db my_database(NULL, 0); // Database open omitted for clarity ? float money = 122.45; Dbt key(&money, sizeof(float)); ? my_database.del(NULL, &key, 0); ? |
del方法并不是真正的物理刪除,db文件的大小也不會變小——這有點象Access。
An Example
| #include "stdafx.h" #include <iostream> #include <db_cxx.h> #include <string.h> ? ? ? using namespace std; int _tmain(int argc, _TCHAR* argv[]) { ?????? Db db(NULL,0); ?????? ?????? u_int32_t oFlags = DB_CREATE; // Open flags; ?????? try ?????? { ????????????? db.open(NULL,??????????????? // Transaction pointer ???????????????????? "my_db.db",????????? // Database file name ??????????? NULL,??????????????? // Optional logical database name ??????????? DB_BTREE,?????? ?????// Database access method ??????????? oFlags,????????????? // Open flags ??????????? 0);????????????????? // File mode (using defaults) ????????????? db.truncate(NULL,0,0); ????????????? float money = 122.45; ????????????? char *description = "Grocery bill."; ? ????????????? Dbt key(&money, sizeof(float)); ????????????? Dbt data(description, strlen(description)+1); ????????????? int ret = db.put(NULL, &key, &data, DB_NOOVERWRITE); ????????????? cout<<"put data--"<<description<<endl; ? ????????????? ret = db.get(NULL, &key, &data, DB_GET_BOTH); ????????????? cout<<"get key--"<<*((float*)key.get_data())<<endl; ????????????? cout<<"get data--"<<(char *)data.get_data()<<endl; ? ????????????? money = 111; ????????????? description = "James--------------------"; ? ???????????? data.set_data(description); ????????????? data.set_size(strlen(description)+1); ????????????? db.put(NULL,&key,&data,DB_NOOVERWRITE); ????????????? ret = db.get(NULL, &key, &data, DB_GET_BOTH); ????????????? cout<<"get key--"<<*((float*)key.get_data())<<endl; ????????????? cout<<"get data--"<<(char *)data.get_data()<<endl; ? ????????????? money = 191; ????????????? description = "Mike"; ? ????????????? data.set_data(description); ????????????? data.set_size(strlen(description)+1); ????????????? db.put(NULL,&key,&data,DB_NOOVERWRITE); ????????????? ret = db.get(NULL, &key, &data, DB_GET_BOTH); ????????????? cout<<"get key--"<<*((float*)key.get_data())<<endl; ????????????? cout<<"get data--"<<(char *)data.get_data()<<endl; ? ? ?????? } ?????? catch(DbException &e) ?????? { ????????????? cerr<<"DBException:"<<e.what(); ?????? } ?????? catch(std::exception &e) ?????? { ????????????? cerr<<"DBException:"<<e.what(); ?????? } ?????? system("pause"); ?????? return 0; } |
?
所有Berkeley DB相關的隨筆
總結
以上是生活随笔為你收集整理的Berkeley DB——Records的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人生失败的31种致命原因
- 下一篇: 查询存在表1但不存在表2的所有数据