Berkeley DB示例程序详解 (1)
本文通过分析Berkeley DB自带的示例程序来详细阐述了使用Berkeley Db基本功能的方法。这之后还将有更多这类文章,我认为通过学习好的例子和已有代码来学习使用berkeley db是很有效的。
/*
* 这个例子程序是Berkeley DB的示例程序之一(DB/example_cxx/AccessMethod.cpp),
* 它演示了如何使用Berkeley DB的基本功能,包括打开一个数据库,存入若干个
* key/data pair,然后遍历数据库中的数据,最后关闭数据库。
*
* 原始代码中有一些英文注释,但是对于初学者还是不够详细,我没有删除原来
* 的注释,而且添加了针对每一个Berkeley DB操作的更加详细的说明,请参考。
*
* 代码的非关键部分都已删除,所以这里的内容
* 无法直接编译运行。可以直接编译运行的版本我会放到空间的附件中。
*
*
* 用词约定:
* 本文提到的“数据库”是指Berkeley DB的database,相当于关系数据库的一个表。
* 一个数据库当中保存着很多个key/data pair,相当于关系数据库的一个表当中
* 保存着很多条记录。也就是说一个key/data pair相当于关系数据库的一条记录。
* 而数据库环境(DbEnv)是指Berkeley Db的执行环境,相当于一个关系数据库管理系统。
*/
/* 测试用例类声明 */
class AccessExample
{
public:
AccessExample();
void run(bool removeExistingDatabase, const char *fileName);
private:
// no need for copy and assignment
AccessExample(const AccessExample &);
void operator = (const AccessExample &);
};
/*
* 这个例子程序演示了如何使用Berkeley DB的基本功能,包括打开一个数据库,存入
* 若干个key/data pair,然后遍历数据库中的数据,最后关闭数据库。
*/
int
main(int argc, char *argv[])
{
// Use a try block just to report any errors.
// An alternate approach to using exceptions is to
// use error models (see DbEnv::set_error_model()) so
// that error codes are returned for all Berkeley DB methods.
//
try {
AccessExample app;
app.run((bool)(rflag == 1 ? true : false), database);
return (EXIT_SUCCESS);
}
catch (DbException &dbe) {
cerr << “AccessExample: ” << dbe.what() << “n”;
return (EXIT_FAILURE);
}
}
void AccessExample::run(bool removeExistingDatabase, const char *fileName)
{
// Remove the previous database.
if (removeExistingDatabase)
(void)remove(fileName);
// Create the database object.
// There is no environment for this simple example.
// 这里我们没有指定显式的environment,BerkeleyDB会在内部创建一个专门供
// 这个数据库使用的environment. 同时,第二个参数表明,当出现错误后,
// Berkeley DB会抛出异常。
Db db(0, 0);
// 当出现运行错误后,错误信息写入cerr流。
//
// Berkeley DB在调试模式下,可以可选地输出非常丰富的错误信息和其他运行期信息,
// 大大简化了调试过程。比如,你可以让Berkeley DB把错误信息写到一个文件、
// 一个c++ io流中,或者调用用户注册的回调函数由用户自己处理错误信息,
// 以及在错误信息中前缀某些自定义信息,等等。
//
// 关于错误报告和调试的文档:
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/debug/runtime.html
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/am_misc/error.html
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/env/error.html
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/program/errorret.html
db.set_error_stream(&cerr);
// 在每个错误信息前缀 “AccessExample”
db.set_errpfx(“AccessExample”);
// 设置数据库页的size为1024字节。数据库页的设置会在较大程度上影响数据库的性能,
// 这里有关于页设置的说明:
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/am_conf/pagesize.html
db.set_pagesize(1024); /* Page size: 1K. */
// 设置cache的大小,数据库的页调入内存后,就放在cache当中,也就是说,cache
// 就是存放调入内存的数据库页面的,如果整个数据库中每一个页面都可以调入
// 内存长期存放,那么数据库的速度自然很快,所以,cache确实是越大越好的,
// 当它大于所有数据库页面所占空间后,对性能就没什么影响了。
//
// 设置cache size的指导 :
// http://www.oracle.com/technology/documentation/berkeley-db/db/api_cxx/frame.html
//
// 如果cache填满了,数据库会淘汰不用的页面,若这样的页面有改动,会写回
// 数据库文件。腾出空间后再调入目标页面。这涉及很多磁盘操作,所以数据库
// 操作会突然变慢很多,应用程序的性能就会偶尔
// 发生短暂地下降。为了避免这种性能抖动,你可以在一个单独运行的线程当中,
// 定期淘汰页面腾出cache的空间,保证cache总是有一定的空间可用,
// 这叫做memory trickle。
//
// 方法见此链接:
// http://www.oracle.com/technology/documentation/berkeley-db/db/api_cxx/frame.html
db.set_cachesize(0, 32 * 1024, 0);
// 打开数据库。这个函数的文档 :
// http://www.oracle.com/technology/documentation/berkeley-db/db/api_cxx/frame.html
//
// 这里创建的是一个btree数据库。Berkeley DB支持四种Access Method,也就是
// 数据库文件内部组织数据的方式,包括btree, hash, queue和record number,
// 分别使用DB_BTREE, DB_HASH, DB_QUEUE和DB_RECNO来指定。
//
// 每一种access method都有自己的优点和缺点,适用于某种需求。所以你应该根据自己
// 的应用程序的数据存储需求,数据访问方式来决定使用哪种access method.
// 关于如何选择合适的access method:
// http://www.oracle.com/technology/documentation/berkeley-db/db/ref/am_conf/select.html
db.open(NULL, fileName, NULL, DB_BTREE, DB_CREATE, 0664);
//
// Insert records into the database, where the key is the user
// input and the data is the user input in reverse order.
//
char buf[1024], rbuf[1024];
char *p, *t;
int ret;
u_int32_t len;
// 循环获取用户输入的字符串str, 把str逆序得到str1, 然后存储(str, str1)
// 作为一个key/data pair.
for (;;) {
cout << “input> “;
cout.flush();
cin.getline(buf, sizeof(buf));
if (cin.eof())
break;
if ((len = (u_int32_t)strlen(buf)) <= 0)
continue;
for (t = rbuf, p = buf + (len – 1); p >= buf;)
*t++ = *p–;
*t++ = ‘