使用
Berkeley DB提
供了多种语言的API,但我使用的是其C++
API,虽然C的API来得最直接,但是对我而言比较难用,没有C++的来得舒服——我比较适应面向对象风格的东西。可惜它的C++
API也没有做足够好的封装,使用者还是要写很多繁复的代码,而且要记住它API中会使用到N多的Flag。因此我又把它C++的API包装了一遍,提供
更为直观的API,舍弃那些通常不会用到的Flag参数。
在使用中,我发现了几个令人感到疑惑和郁闷的问题(可能是我水平有限的缘故):
1、.DB文件的文件名仅支持char*的,这在国际化软件环境中会是一个问题。
2、
不支持直接存入string和wstring类型的数据。STL是人们在使用C++过程中普遍会用到的,而若你直接往Berkeley
DB中存入string和wstring(或者Field的类型为string和wstring的结构体)的话,那你将得到不正确的结果——存入数据
后,API返回sucess,但是当你把数据再取出时,只能是最后存入的那对key/data,且data中的内容部分字节发生了乱码,比如你在data
中存入了hello,那可能取出的内容中前面的字符是he,而后面的字符都是乱码。
3、说是支持重复记录(duplicate records),但是当我按照其示例代码调用相应的API时,却发生异常:无效的参数!真不知道Sleepycat哪个环节的工作出了问题。
4、其源码说是可以使用vs2005编译,但是使用vs2005编译会出现大把大把的错误,而使用vc6编译则无问题。
示例
下面是我测试其duplicate records的代码(执行并不成功,报“无效的参数”):
{
int ret = 0;
Db db(NULL,0);
ret = db.set_flags(DB_DUP);
ret = db.open(NULL,"multi.db",NULL,DB_BTREE,DB_CREATE,0);
ret = db.truncate(NULL,0,0);
Dbt key,data;
char *strk,*strd;
strk = "001";
key.set_data(strk);
key.set_size(strlen(strk)+1);
strd = "data1";
data.set_data(strd);
data.set_size(strlen(strd)+1);
ret = db.put(NULL,&key,&data,0);
strd = "data2";
data.set_data(strd);
data.set_size(strlen(strd)+1);
ret = db.put(NULL,&key,&data,0);
strd = "data3";
data.set_data(strd);
data.set_size(strlen(strd)+1);
ret = db.put(NULL,&key,&data,0);
Dbt dataBuffer;
dataBuffer.set_data(&strd);
dataBuffer.set_ulen(6*1024);
dataBuffer.set_flags(DB_DBT_USERMEM);
try
{
ret = db.get(NULL,&key,&dataBuffer,DB_MULTIPLE);
}
catch (DbException &e)
{
cout<<" "<<e.what();
}
DbMultipleDataIterator iterator(dataBuffer);
Dbt mdata;
while ( iterator.next(mdata) == true )
{
char *str = (char*)mdata.get_data();
cout<<"data: "<<str<<endl;
}
}
posted on 2006-04-12 15:43 风满袖 阅读(1546) 评论(3) 编辑 收藏 网摘 所属分类: Database
评论
#1楼
2006-05-21 11:22
ipiggg [未注册用户]
下面是IBM的页面(http://www-128.ibm.com/developerworks/cn/linux/l-embdb/?ca=dwcn-newsletter-linux#resources)上的一个例子
和你的例子有2点不同
1:没有初始化DBT类型的key,data
2:下面的程序有这么一段 “/* 把记录写入数据库中,不允许覆盖关键字相同的记录 */
ret = dbp->put(dbp, NULL, &key, &data,DB_NOOVERWRITE); ” ,我不知道你的程序怎么处理的。
#include <db.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
/* DB的函数执行完成后,返回0代表成功,否则失败 */
void print_error(int ret)
{
if(ret != 0)
printf("ERROR: %s/n",db_strerror(ret));
}
/* 数据结构DBT在使用前,应首先初始化,否则编译可通过但运行时报参数错误 */
void init_DBT(DBT * key, DBT * data)
{
memset(key, 0, sizeof(DBT));
memset(data, 0, sizeof(DBT));
}
void main(void)
{
DB *dbp;
DBT key, data;
u_int32_t flags;
int ret;
char *fruit = "apple";
int number = 15;
typedef struct customer
{
int c_id;
char name[10];
char address[20];
int age;
} CUSTOMER;
CUSTOMER cust;
int key_cust_c_id = 1;
cust.c_id = 1;
strncpy(cust.name, "javer", 9);
strncpy(cust.address, "chengdu", 19);
cust.age = 32;
/* 首先创建数据库句柄 */
ret = db_create(&dbp, NULL, 0);
print_error(ret);
/* 创建数据库标志 */
flags = DB_CREATE;
/* 创建一个名为single.db的数据库,使用B+树访问算法,本段代码演示对简单数据类型的处理 */
ret = dbp->open(dbp, NULL, "single.db", NULL, DB_BTREE, flags, 0);
print_error(ret);
init_DBT(&key, &data);
/* 分别对关键字和数据赋值和规定长度 */
key.data = fruit;
key.size = strlen(fruit) + 1;
data.data = &number;
data.size = sizeof(int);
/* 把记录写入数据库中,不允许覆盖关键字相同的记录 */
ret = dbp->put(dbp, NULL, &key, &data,DB_NOOVERWRITE);
print_error(ret);
/* 手动把缓存中的数据刷新到硬盘文件中,实际上在关闭数据库时,数据会被自动刷新 */
dbp->sync();
init_DBT(&key, &data);
key.data = fruit;
key.size = strlen(fruit) + 1;
/* 从数据库中查询关键字为apple的记录 */
ret = dbp->get(dbp, NULL, &key, &data, 0);
print_error(ret);
/* 特别要注意数据结构DBT的字段data为void *型,所以在对data赋值和取值时,要做必要的类型转换。 */
printf("The number = %d/n", *(int*)(data.data));
if(dbp != NULL)
dbp->close(dbp, 0);
ret = db_create(&dbp, NULL, 0);
print_error(ret);
}