在网上看到不少介绍Berkeley DB的文章,几乎所有的中文文章都是介绍完入门就再也没了。大都是个概括。最近做这个,所以想系统的由浅入深的介绍一下。不清楚的地方可以和我讨论,或参照官方网站sleepycat上的文档。我用的是最新版本 db-4.4.16.NC.tar.gz,这个包中含有详细的英文文档。
为什么要使用Berkeley DB,它适合什么场合应用?
Berkeley DB并不适合所有的应用,因为简单,专一所以高效。
嵌入式数据库,的“嵌入”是指它内嵌在程序中,而不是说他只应用在嵌入式系统上。它的特点很适合应用于嵌入式系统上。当然在我们的pc机集群或大型服务器上,也可以灵活的配置,完成更艰巨的任务。
它适合于管理海量的,简单的数据。Google用Berkeley DB HA (High Availability) 来管理他们的帐户信息. Motorola在他的无线产品中用Berkeley DB跟踪移动单元。hp,microsoft,Sun Microsystems...等也都是它的大客户。它不能完全取代关系数据库,但在某些方面,它却有他们望尘莫及的高效性。
性能测试,在如下的配置上:
Linux – SuSE Linux 9.1 running on an AMD Athlon 64 processor 3200+ at 1GHz system with 1GB of RAM。
每秒钟,单条记录读操作 1,002,200次。单条记录写操作 766,034次。 用bulk APIs能进行读操作 13,501,800次。当然这些都是发生在内存中的操作,因为bdb使用了cache。 性能测试具体数据可以参考官方网站的Performance Metrics & Benchmarks: Berkeley DB。
Berkeley DB简介
Berkeley DB可以说是一个专为程序员准备的数据库。我的文章中只针对c程序员介绍的。它还支持C++、Java、Perl、Tcl、Python和PHP等。原理和接口都差不多。它的安装很简单。
cd build_unix
../dist/configure
make
make install
这几步就ok了,其实也就是把头文件和编译好的db库放到指特定位置。甚至可以不用make install,直接在编译你的程序时用-I -L -ldb 指定头文件和连接库的位置。可以完全把它当作一个函数库来用。由db库透明的来完成对数据的管理。无论是系统中的多个进程,或者是相同进程中的多个线程,都可以在同一时间调用访问数据库的函数。而底层的数据加锁、事务日志和存储管理等都在Berkeley DB函数库中实现。他不像传统的数据库那样有client和server,还专门跑几个进程。所以应用程序不需要事先同数据库服务建立起网络连接,而是通过内嵌在程序中的Berkeley DB函数库来完成对数据的保存、查询、修改和删除等操作。
Berkeley DB函数库本身虽然只有300KB左右,但却能够用来管理多达256TB的数据,并且在许多方面的性能还能够同商业级的数据库系统相抗衡。就拿对数据的并发操作来说,Berkeley DB能够很轻松地应付几千个用户同时访问同一个数据库的情况。因而,在资源受限的嵌入式系统上进行数据库管理,Berkeley DB也是一个不错的选择。
Berkeley DB为何高效?
Berkeley DB作为一种嵌入式数据库系统在许多方面有着独特的优势。首先,由于其应用程序和数据库管理系统运行在相同的进程空间当中,进行数据操作时可以避免繁琐的进程间通信包括建立socket连接等,因此耗费在通信上的开销自然也就降低到了极低程度。其次,Berkeley DB使用简单的函数调用接口来完成所有的数据库操作,而不是在数据库系统中经常用到的SQL语言。这样就避免了对结构化查询语言进行解析和处理所需的开销。
基本概念
关键字/数据 是Berkeley DB用来进行数据库管理的基础。每个 Key/Data 对构成一条记录。而整个数据库实际上就是由许多这样的结构单元所构成的。通过使用这种方式,开发人员在使用Berkeley DB提供的API来访问数据库时,只需提供关键字就能够访问到相应的数据。当然也可以也可以提供 Key 和部分Data来查询符合条件的相近数据。
一个例子来完成入门
使用过rdb的人相信都能看的懂下面的例子。简要的说一下下面持续完成的功能。作为一个简单的例子environment部分可以不是必要的,我把它的用法也一起加了进来。创建一个environment指明要把数据库文件创建到哪个目录下面。创建数据库,打开数据库,写一个记录进去,然后读出记录,然后将写入的记录删除,然后关闭environment和数据库。会了这些基本操作,你就可以使用bdb完成简单的应用了。
....................................................................
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//only this head should include for use bdb.
#include <db.h>
#define DATABASE "yangjian.db"
int main()
{
DB_ENV *myEnv;
DB *dbp;
DBT key, data;
int ret,t_ret;
u_int32_t env_flags;
//........... Create an environment object and initialize it for error reporting
ret = db_env_create(&myEnv, 0);
if (ret != 0)
{
fprintf(stderr, "Error creating env handle: %s\n", db_strerror(ret));
return -1;
}
//........If the environment does not exist create it. Initialize the in-memory cache.
env_flags = DB_CREATE | DB_INIT_MPOOL;
//........Open the environment.
ret = myEnv->open(myEnv,"/home/yangbin1/yangjian/my/db/testevn",env_flags,0);
if (ret != 0)
{
fprintf(stderr, "Environment open failed: %s", db_strerror(ret));
return -1;
}
if ((ret = db_create(&dbp, myEnv, 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");
/*
//......put data
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");
}
*/
//........put data 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");
//.......get data
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");
//......del data
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");
//.........close, only when the db successful closed,the data can real write to the disk.
//if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
//ret = t_ret;
//exit(ret);
if (dbp != NULL)
dbp->close(dbp, 0);
//.........close evn
//........When you are done with an environment, you must close it.
//........Before you close an environment, make sure you close any opened databases
if (myEnv != NULL)
myEnv->close(myEnv, 0);
return 0;
}
....................................................................
为什么要使用Berkeley DB,它适合什么场合应用?
Berkeley DB并不适合所有的应用,因为简单,专一所以高效。
嵌入式数据库,的“嵌入”是指它内嵌在程序中,而不是说他只应用在嵌入式系统上。它的特点很适合应用于嵌入式系统上。当然在我们的pc机集群或大型服务器上,也可以灵活的配置,完成更艰巨的任务。
它适合于管理海量的,简单的数据。Google用Berkeley DB HA (High Availability) 来管理他们的帐户信息. Motorola在他的无线产品中用Berkeley DB跟踪移动单元。hp,microsoft,Sun Microsystems...等也都是它的大客户。它不能完全取代关系数据库,但在某些方面,它却有他们望尘莫及的高效性。
性能测试,在如下的配置上:
Linux – SuSE Linux 9.1 running on an AMD Athlon 64 processor 3200+ at 1GHz system with 1GB of RAM。
每秒钟,单条记录读操作 1,002,200次。单条记录写操作 766,034次。 用bulk APIs能进行读操作 13,501,800次。当然这些都是发生在内存中的操作,因为bdb使用了cache。 性能测试具体数据可以参考官方网站的Performance Metrics & Benchmarks: Berkeley DB。
Berkeley DB简介
Berkeley DB可以说是一个专为程序员准备的数据库。我的文章中只针对c程序员介绍的。它还支持C++、Java、Perl、Tcl、Python和PHP等。原理和接口都差不多。它的安装很简单。
cd build_unix
../dist/configure
make
make install
这几步就ok了,其实也就是把头文件和编译好的db库放到指特定位置。甚至可以不用make install,直接在编译你的程序时用-I -L -ldb 指定头文件和连接库的位置。可以完全把它当作一个函数库来用。由db库透明的来完成对数据的管理。无论是系统中的多个进程,或者是相同进程中的多个线程,都可以在同一时间调用访问数据库的函数。而底层的数据加锁、事务日志和存储管理等都在Berkeley DB函数库中实现。他不像传统的数据库那样有client和server,还专门跑几个进程。所以应用程序不需要事先同数据库服务建立起网络连接,而是通过内嵌在程序中的Berkeley DB函数库来完成对数据的保存、查询、修改和删除等操作。
Berkeley DB函数库本身虽然只有300KB左右,但却能够用来管理多达256TB的数据,并且在许多方面的性能还能够同商业级的数据库系统相抗衡。就拿对数据的并发操作来说,Berkeley DB能够很轻松地应付几千个用户同时访问同一个数据库的情况。因而,在资源受限的嵌入式系统上进行数据库管理,Berkeley DB也是一个不错的选择。
Berkeley DB为何高效?
Berkeley DB作为一种嵌入式数据库系统在许多方面有着独特的优势。首先,由于其应用程序和数据库管理系统运行在相同的进程空间当中,进行数据操作时可以避免繁琐的进程间通信包括建立socket连接等,因此耗费在通信上的开销自然也就降低到了极低程度。其次,Berkeley DB使用简单的函数调用接口来完成所有的数据库操作,而不是在数据库系统中经常用到的SQL语言。这样就避免了对结构化查询语言进行解析和处理所需的开销。
基本概念
关键字/数据 是Berkeley DB用来进行数据库管理的基础。每个 Key/Data 对构成一条记录。而整个数据库实际上就是由许多这样的结构单元所构成的。通过使用这种方式,开发人员在使用Berkeley DB提供的API来访问数据库时,只需提供关键字就能够访问到相应的数据。当然也可以也可以提供 Key 和部分Data来查询符合条件的相近数据。
一个例子来完成入门
使用过rdb的人相信都能看的懂下面的例子。简要的说一下下面持续完成的功能。作为一个简单的例子environment部分可以不是必要的,我把它的用法也一起加了进来。创建一个environment指明要把数据库文件创建到哪个目录下面。创建数据库,打开数据库,写一个记录进去,然后读出记录,然后将写入的记录删除,然后关闭environment和数据库。会了这些基本操作,你就可以使用bdb完成简单的应用了。
....................................................................
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//only this head should include for use bdb.
#include <db.h>
#define DATABASE "yangjian.db"
int main()
{
DB_ENV *myEnv;
DB *dbp;
DBT key, data;
int ret,t_ret;
u_int32_t env_flags;
//........... Create an environment object and initialize it for error reporting
ret = db_env_create(&myEnv, 0);
if (ret != 0)
{
fprintf(stderr, "Error creating env handle: %s\n", db_strerror(ret));
return -1;
}
//........If the environment does not exist create it. Initialize the in-memory cache.
env_flags = DB_CREATE | DB_INIT_MPOOL;
//........Open the environment.
ret = myEnv->open(myEnv,"/home/yangbin1/yangjian/my/db/testevn",env_flags,0);
if (ret != 0)
{
fprintf(stderr, "Environment open failed: %s", db_strerror(ret));
return -1;
}
if ((ret = db_create(&dbp, myEnv, 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");
/*
//......put data
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");
}
*/
//........put data 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");
//.......get data
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");
//......del data
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");
//.........close, only when the db successful closed,the data can real write to the disk.
//if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
//ret = t_ret;
//exit(ret);
if (dbp != NULL)
dbp->close(dbp, 0);
//.........close evn
//........When you are done with an environment, you must close it.
//........Before you close an environment, make sure you close any opened databases
if (myEnv != NULL)
myEnv->close(myEnv, 0);
return 0;
}
....................................................................