Berkeley DB 4.8 的 dbstl API
Berkeley DB 4.8 刚刚发布,我的心情格外激动。不仅仅是因为这个版本
是Berkeley DB新增了很多新功能,在很多方面有不小的增强,更因为在
众多的新功能中,有主要由我设计开发的STL API。 作为增强Berkeley DB的
易用性或者叫做用户友好性的重要组成部分,STL API是Berkeley DB4.8
的主要的新特性之一。
Berkeley DB的STL API也叫做dbstl或者DB STL, 它的作用是让C++程序员更加容易地
使用Berkeley DB嵌入式数据库。如果你用过Berkeley DB的C/C++ API, 你就会
发现,C++ API是对C API的非常简单的封装,并没有体现出C++语言在软件
设计方面的优势,它的易用性并不好。
STL API 就是为了增强Berkeley DB
的易用性而设计的。使用Berkeley DB STL API, 你就好像在使用C++ STL类库
一样:你操纵的是容器和iterator, 向容器中插入数据,数据就插入到了
Berkeley DB数据库中;使用iterator遍历容器,就可以遍历数据库中的数据。
而且你不需要与Dbt, Dbc, DbTxn等类型的对象打交道,不需要每次存储或者
读取数据,都封装到一个Dbt对象(也叫做marshal),或者从Dbt对象中读取出
数据(也叫做unmarshal)。你只需要像使用C++ STL容器类和
iterator那样使用dbstl,就可以插入/删除/更新/查询 Berkeley DB数据库;
同时,你也不需要手动关闭cursor, transaction,
database, environment,还要保证正确的关闭顺序 — 它们的生命周期由
dbstl自动正确地管理。
dbstl被设计成几乎完全符合C++ STL规范,所以你可以像使用C++ STL
的容器和iterator那样使用 dbstl. 比如它的iterator符合C++ STL 的
规定,这样,c++ STL的算法就可以通过STL API
操纵Berkeley DB中的数据; c++ STL 的 container adapters, 诸如std::stack,
std::queue和std::priority_queue可以使用dbstl::db_vector 容器,这样
我们就可以非常轻易地用Berkeley DB数据库建立栈,队列,优先级队列。事实上,
如果你有一段使用了C++ STL的代码,你只需要替换容器类模板的名称,
以及其他一些微小的改动,你就可以使用dbstl了。
Dbstl的性能开销很小,而且有较好的可移植性。只要一个平台支持Berkeley DB,
并且拥有一个符合ISO C++标准的编译器,就一定可以使用dbstl. gcc3.4.4及以上,
intel c++ compiler 9及以上,以及msvc8,都是经验正支持dbstl的编译器。而且
dbstl通过了MS的STL测试包,以及SGI STL的测试包, 也就是说,它是符合C++ STL
标准的,你完全可以当dbstl是一个标准的c++ STL类库来使用它。
DB STL 的典型用例:
1. 当你的程序操纵着很大量的数据,无法容纳在内存当中的时候。此时C++ STL
会导致频繁的操作系统页交换,使得整台机器性能显著下降;如果使用dbstl,那么
由于Berkeley DB的缓存管理功能,只有用到的数据被保留在内存当中,
所以机器的全局性能不会受到任何影响。
2. 你希望使用一个熟悉的接口来使用Berkeley DB.
dbstl为Berkeley DB提供了一个熟悉的接口,因为几乎每一个c++程序员都接触过STL类库。
Berkeley DB特有的繁琐的DBT, DBC, DB_TXN等等的操作都被隐藏起来了。
3. 你需要拥有事务语义的数据结构。dbstl可选的提供了事务的ACID属性,并且支持全部的
C++ STL 容器功能。
4. 并发的访问控制
目前几乎所有的C++ STL实现只支持并发访问一个容器类的不同的容器对象。当你需要并发
地访问同一个容器对象时候,都需要显式的mutex保护。而使用dbstl的话,你就可以并发
地在多线程当中访问同一个容器对象,甚至并发地在多个进程当中通过各个进程当中的
容器对象操纵同一个数据库,并发访问的灵活性大大增加。
5. 对象持久化
dbstl允许你的程序在数据库中存储对象,并且在你的程序的多次运行之间存储和复活对象。
而且在用户提供适当的回调函数后,dbstl可以存储任意复杂的对象。
作为dbstl的主要设计和开发者, 毫不夸张地说,目前我是这个世界上最熟悉dbstl的人了,呵呵。
欢迎使用Berkeley DB的这个新功能,如果遇到问题可以在这里问我,或者到
Oracle Technology Network上面的Berkeley DB版面提问。
附注:
dbstl的参考文档: http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/index.html 的第 7 章
dbstl 的类/函数 文档: http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/STL/frame_main.html
dbstl示例代码: Berkeley DB source root/examples_stl里面有若干个示例程序;在 Berkeley DB source root/test_stl/base 里面,有针对dbstl的所有功能点的测试代码,可以作为学习使用dbstl的功能的示例代码。
good work! + orz
因为升级会折腾之前写好的一部分代码,在下载新版本之前问个问题
这些STL的API内部对于某些批量的赋值操作是调用的新版本的批量插入还是沿用从前的一个一个数据项插入?
呃。。安装之后发现include里面没有stl相关的文件。。还要装点什么不。。
不知david兄看了代码后觉得方案可不可行啊?
Hi 林林,
真诚的谢谢你对DBSTL的支持和兴趣,也谢谢你的代码。由于David目前在忙一些更重要的项目,所以他可能要晚点回复你。希望你理解。
了解
问题报告:
class TlsWrapper这个类里面定义了一个静态成员static TLS_DECL_MODIFIER T *tinst_;,这样的话,在dll工程里无论是动态链接或静态链接libdb_stl48sd.lib,会出问题,导致运行到
if ((pinst = TlsWrapper::get_tls_obj()) == NULL)直接出错,
static T *get_tls_obj()
{
return tinst_;
}
这时候return tinst_;返回的将是一个空指针。如果工程是exe类型则无此问题!
不过在dll或lib工程里定义static变量是老大难问题,也不能算是bug,就是不知道有什么好的解决方案?
在程序库里定义static变量,然后让dll调用,确实好像没有什么好的解决办法。现在唯一想到的解决办法就是在dll工程里加入整个dbstl的源代码,然后再编译,不调用任何libdb_stl48*.lib或dll,应该没问题。
这应该算是不是解决办法的解决办法。
更正。这时候return tinst_;返回的将是一个空指针。如果工程是exe类型则无此问题.这句话不够精确。应该说是return tinst_将会产生非法操作。因为tinst_这时候指向的地址是不存在的地址。
在dll工程下链接dbstl的问题找到了。由于dbstl使用了线程本地存储,所以不能用loadlibrary或loadlibraryex来动态调用。改用静态调用就行了。
很好。我打算用这个。对one-to-many型的映射搞不太明白,请楼主指教。我看了c++ db4.8api,好像这个支持不是很好,需要映射一个key[],数组的,也就是说大小是定值。dbstl这方面有什么改进吗?
还有,dbstl缺少文档。只找到一篇这个
http://www.linuxjournal.com/article/9374
In file included from d:/Oracle/BDB4.8.24/include/dbstl_container.h:13,
from d:/Oracle/BDB4.8.24/include/dbstl_dbc.h:18,
from d:/Oracle/BDB4.8.24/include/dbstl_map.h:15,
from StlAccessExample.cpp:18:
d:/Oracle/BDB4.8.24/include/dbstl_resource_manager.h:118: warning: `thread’ attr ibute directive ignored
In file included from StlAccessExample.cpp:18:
d:/Oracle/BDB4.8.24/include/dbstl_map.h:681: error: explicit specialization in n on-namespace scope `class dbstl::db_map_base_iterator’
d:/Oracle/BDB4.8.24/include/dbstl_map.h:681: error: enclosing class templates ar e not explicitly specialized
d:/Oracle/BDB4.8.24/include/dbstl_map.h:685: error: non-member function `void db stl::assign_second0(std::pair&, const dbstl::_DB_STL_set_value&)’ cannot have `const’ method qualifier
d:/Oracle/BDB4.8.24/include/dbstl_map.h:685: error: `assign_second0′ is not a te mplate function
d:/Oracle/BDB4.8.24/include/dbstl_map.h:685: error: invalid function declaration
d:/Oracle/BDB4.8.24/include/dbstl_map.h:1094: error: explicit specialization in non-namespace scope `class dbstl::db_map_iterator’
d:/Oracle/BDB4.8.24/include/dbstl_map.h:1094: error: enclosing class templates a re not explicitly specialized
d:/Oracle/BDB4.8.24/include/dbstl_map.h:1098: error: non-member function `void d bstl::assign_second(std::pair&, const dbstl::_DB_STL_set_va lue&)’ cannot have `const’ method qualifier
d:/Oracle/BDB4.8.24/include/dbstl_map.h:1098: error: `assign_second’ is not a te mplate function
d:/Oracle/BDB4.8.24/include/dbstl_map.h:1098: error: invalid function declaratio n
好了。编译了一下。
请教为什么dbstl_startup不能执行两次?
dbstl_startup()
dbstl_exit();
dbstl_startup();
dbstl_exit();
立马出错!