应用统一的编程接口
使用Berkeley DB提供的函数来进行数据库的访问和治理并不复杂,在大多数场合下只需按照统一的接口标准进行调用就可以完成最基本的操作。
打开数据库
打开数据库通常要分两步进行:首先调用db_create()函数来创建DB结构的一个实例,然后再调用DB-open()函数来完成真正的打开操作。Berkeley DB将所有对数据库的操作都封装在名为DB的结构中。db_create()函数的作用就是创建一个该结构,其原型如下所示:
typedef strUCt__db DB;
int db_create(DB **dbp, DB_ENV *dbenv, u_int32_t flags);
将磁盘上保存的文件作为数据库打开是由DB-open()函数来完成的,其原型如下所示:
int DB-open(DB *db, DB_TXN *txnid, const char *file,
const char *database, DBTYPE type, u_int32_t flags, int mode);
下面这段代码示范了如何创建DB对象句柄及如何打开数据库文件:
#include <sys/types.h
#include <stdio.h
#include <stdlib.h
#include <string.h
#include <db.h
#defineDATABASE "demo.db"
/* 以下程序代码的程序头同此*/
int main()
{DB *dbp;
int ret;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp-open(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp-err(dbp, ret, "%s", DATABASE);
exit (1);
}
}
代码首先调用db_create()函数来创建一个DB对象句柄。变量dbp在调用成功后将成为数据库句柄,通过它可以完成对底层数据库的配置或访问。接下去调用DB-open()函数打开数据库文件,参数“DATABASE”指明对应的磁盘文件名为demo.db;参数“DB_BTREE”表示数据库底层使用的数据结构是B树;而参数“DB_CREATE”和“0664”则表明当数据库文件不存在时创建一个新的数据库文件,并且将该文件的属性值设置为0664。
错误处理是在打开数据库时必须的例行检查,这可以通过调用DB-err()函数来完成。其中参数“ret”是在调用Berkeley DB函数后返回的错误代码,其余参数则用于显示结构化的错误信息。
添加数据
向Berkeley DB数据库中添加数据可以通过调用DB-put()函数来完成,其原型如下所示:
int DB-put(DB *db,DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags);
下面这段代码示范了如何向数据库中添加新的数据:
int main()
{DB *dbp;
DBT key, data;
int ret;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp-open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp-err(dbp, ret, "%s", DATABASE);
exit (1);
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = "sport";
key.size = sizeof("sport");
data.data = "football";
data.size = sizeof("football");
if ((ret = dbp-put(dbp, NULL, &key, &data, 0)) == 0)
printf("db: %s: key stored.\n", (char *)key.data);
else
dbp-err(dbp, ret, "DB-put");
}
代码首先声明了两个DBT结构变量,并分别用字符串“sport”和“football”进行填充。它们随后作为要害字和数据传递给用来添加数据的DB-put()函数。DBT结构几乎会在所有同数据访问相关的函数中被用到。
在向数据库中添加数据时,假如给定的要害字已经存在,大多数应用会对于已经存在的数据采用覆盖原则。也就是说,假如数据库中已经保存了一个“sport/basketball”对,再次调用DB-put()函数添加一个“sport/football”对,那么先前保存的那些数据将会被覆盖。但Berkeley DB答应在调用DB-put()函数时指定参数“DB_NOOVERWRITE”,声明不对数据库中已经存在的数据进行覆盖,其代码如下:
if ((ret = dbp-put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) == 0)
printf("db: %s: key stored.\n", (char *)key.data);
else
dbp-err(dbp, ret, "DB-put");
一旦给出“DB_NOOVERWRITE”标记,假如DB-put()函数在执行过程中发现给出的要害字在数据库中已经存在了,就无法成功地把该Key/Data对添加到数据库中,于是将返回错误代号“DB_KEYEXIST”。
检索数据
从Berkeley DB数据库中检索数据可以通过调用DB-get()函数来完成,其原型如下所示:
int DB-get(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags);
下面这段代码示范了如何从数据库中检索出所需的数据:
int main()
{DB *dbp;
DBT key, data;
int ret;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp-open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp-err(dbp, ret, "%s", DATABASE);
exit (1);
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = "sport";
key.size = sizeof("sport");
if ((ret = dbp-get(dbp, NULL, &key, &data, 0)) == 0)
printf("db: %s: key retrieved: data was %s.\n",
(char *)key.data, (char *)data.data);
else
dbp-err(dbp, ret, "DB-get");
}
代码同样声明了两个DBT结构变量,并且调用memset()函数对它们的内容清空。虽然Berkeley DB并不强制要求在进行数据操作之前先清空它们,但出于提高代码质量考虑还是建议先进行清空操作。在进行数据检索时,对DB-get()函数的返回值进行处理是必不可少的,因为它携带着检索操作是否成功完成等信息。下面列出的是DB-get()函数的返回值:
◆ 0 函数调用成功,指定的要害字被找到;
◆ DB_NOTFOUND 函数调用成功,但指定的要害字未被找到;
◆大于0 函数调用失败,可能出现了系统错误。
删除数据
从Berkeley DB数据库中删除数据可以通过调用DB-del()函数来完成,其原型如下所示:
int DB-del(DB *db, DB_TXN *txnid, DBT *key, u_int32_t flags);
下面这段代码示范了如何从数据库中删除数据:
int main()
{DB *dbp;
DBT key;
int ret;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp-open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp-err(dbp, ret, "%s", DATABASE);
exit (1);
}
memset(&key, 0, sizeof(key));
key.data = "sport";
key.size = sizeof("sport");
if ((ret = dbp-del(dbp, NULL, &key, 0)) == 0)
printf("db: %s: key was deleted.\n", (char *)key.data);
else
dbp-err(dbp, ret, "DB-del");
}
删除数据只需给出相应的要害字,不用指明与之对应的数据。
关闭数据库
对于一次完整的数据库操作过程来说,关闭数据库是不可或缺的一个环节。这是因为Berkeley DB需要依靠于系统底层的缓冲机制,也就是说只有在数据库正常关闭的时候,修改后的数据才有可能全部写到磁盘上,同时它所占用的资源也才能真正被全部释放。关闭数据库的操作是通过调用DB-close()函数来完成的,其原型如下所示:
int DB-close(DB *db, u_int32_t flags);
下面这段代码示范了如何在需要的时候关闭数据库:
int main()
{DB *dbp;
DBT key, data;
int ret, t_ret;
if ((ret = db_create(&dbp, NULL, 0)) != 0) {
fprintf(stderr, "db_create: %s\n", db_strerror(ret));
exit (1);
}
if ((ret = dbp-open(dbp,
NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
dbp-err(dbp, ret, "%s", DATABASE);
goto err;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = "sport";
key.size = sizeof("sport");
if ((ret = dbp-get(dbp, NULL, &key, &data, 0)) == 0)
printf("db: %s: key retrieved: data was %s.\n",
(char *)key.data, (char *)data.data);
else
dbp-err(dbp, ret, "DB-get");
if ((t_ret = dbp-close(dbp, 0)) != 0 && ret == 0)
ret = t_ret;
exit(ret);
}
小结
Berkeley DB这个嵌入式数据库系统使用非常简单。它没有数据库服务器的概念,也不需要复杂的SQL语句,所有对数据的操作和治理都可以