开源中文网

您的位置: 首页 > 数据库应用 > Berkeley DB > 正文

如何操作Berkeley DB的Records

来源:  作者:

Key/Data Pair and Dbt object

Berkeley DB中保存的是key/data对,它们都是Dbt对象:

 

#include
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
#include
...
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
#include
...
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 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
#include
#include
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--"<<< SPAN>
              ret = db.get(NULL, &key, &data, DB_GET_BOTH);
              cout<<"get key--"<<*((float*)key.get_data())<< SPAN>
              cout<<"get data--"<<(char *)data.get_data()<< SPAN>
              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())<< SPAN>
              cout<<"get data--"<<(char *)data.get_data()<< SPAN>
              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())<< SPAN>
              cout<<"get data--"<<(char *)data.get_data()<< SPAN>
       }
       catch(DbException &e)
       {
              cerr<<"DBException:"<<>
       }
       catch(std::exception &e)
       {
              cerr<<"DBException:"<< SPAN>
       }
       system("pause");
       return 0;
}

Tags:如何 操作 Berkeley
关于开源中文网 - 联系我们 - 广告服务 - 网站地图 - 版权声明