Berkeley DB——Records

Berkeley DB——Records

 

本文主要讲述如何操作Berkeley DB的记录——RecordsCreateRetrieveUpdateDelete

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对象的datalen,以指明需要保存的数据和数据所占用空间的大小——不是指针的大小而是实际数据所占空间的大小。当写数据到DB中的时候,我们需要设置key/data对的sizedata。存入的数据最好是那些c/c++的基本数据类型——比如我们想存入字符串,那应该使用char*或者wchar_t*类型,而不是string或者wstring。根据我的实践,如果存入stringwstring会发生一些奇怪的问题,具体看这里。

如果数据库不允许重复记录的话(默认情况,如果想存入重复记录需要对Db设置相应的flag),put方法就相当于关系数据库中的insert or update

int Db::put(DbTxn *txnid, Dbt *key, Dbt *data, u_int32_t flags);

我们可以给put方法传入不同的flag来控制put的具体行为,这些flag有:

FlagDb.put

Description

0

添加数据到数据库中。如果DB不允许重复记录,当已经有相同的key的记录时,将修改原记录,否则存入新记录;如果DB允许重复,则添加新记录。

DB_APPEND

只针对QueueRecnoDB,将记录添加到数据库的末尾

DB_NODUPDATA

只针对B树和HashDB,且数据库需要设置为允许重复记录,如果不存在相同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

keydata都匹配时,填充data参数

DB_SET_RECNO

根据行号来搜索记录,keydata参数都将被填充(仅针对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相关的随笔

posted @ 2006-04-24 10:47 风满袖 阅读(...) 评论(...) 编辑 收藏