从概念上讲,Berkeley DB数据库是一个包含两列的表,其中第1列存放键值,第2列存放键值对应的数据。使用DBT类的实例(这个类的详细信息,请参阅数据库记录)键和数据管理。所以,从根本上说,使用DB数据库涉及到写入,读取取和删除数据库记录,遍历涉及高效地管理信息封装DBT对象。接下来的几个章节,这本书详细讲述这些操作。
你打开一个数据库实例DB对象,然后调用open()方法。
请注意,默认情况下,如果数据库不存在,不会自动创建数据库,要覆盖此行为,open()方法要指定DB_CREATE的标志。
下面的代码片段说明打开数据库:
#include <db_cxx.h>
...
Db db(NULL, 0); // Instantiate the Db object
u_int32_t oFlags = DB_CREATE; // Open flags;
try {
// Open thedatabase
db.open(NULL, //Transaction pointer
"my_db.db", //Database file name
NULL, // Optional logical databasename
DB_BTREE, // Databaseaccess method
oFlags, // Open flags
0); // File mode(using defaults)
// DbException is not subclassed from std::exception, so
// need to catch both of these.( DbException不是std::exception的子类,所以两个都需要catch)
} catch(DbException &e) {
// Errorhandling code goes here
} catch(std::exception &e) {
// Errorhandling code goes here
}
一旦你使用完数据库,则必须将其关闭。您可以使用DB:: close()方法来关闭数据库。
关闭数据库之前,你应该确保关闭所有打开的游标,未关闭数据库游标,直接关闭数据库可能会导致意想不到的结果,特别是如果这些游标正执行写操作。要知道,当你关闭最后一个打开的数据库句柄,默认情况下,它会把高速缓存区的数据刷新到磁盘,这意味数据库最后一个句柄关闭前,要求所有高速缓存中的数据全都修改完成。
您可以手动执行DB:: sync()方法刷新高速缓存数据到磁盘,但正常关闭时这样操作这是没有必要的。如需同步缓存的更多信息,请参阅数据持久性。
下面的代码片段说明了一个数据库关闭:
#include <db_cxx.h>
...
Db db(NULL, 0);
// Database openand access operations happen here.
try {
// Close thedatabase
db.close(0);
// DbException is not subclassed from std::exception, so
// need to catch both of these.
} catch(DbException &e) {
// Errorhandling code goes here
} catch(std::exception &e) {
// Errorhandling code goes here
}
以下是在数据库打开时,你可能要使用的标志。请注意,这个清单并不详尽 - 它仅包括那些标志介绍,单线程的数据库应用程序可能会感兴趣的。标志提供给您的完整列表,请参阅Berkeley DB的C + + API指南。
注意:要指定多个标志在DB:: open()的调用,你必须按位(与)或:
u_int32_t类型open_flags= DB_CREATE| DB_EXCL;
•DB_CREATE:如果数据库当前不存在,创建它。默认情况下,如果数据库不存在,打开数据库会失败。
•DB_EXCL:新建数据库。如果数据库已经存在,使数据库打开失败。这个标志只有和DB_CREATE才有意义。
•DB_RDONLY:打开数据库进行读操作。导致此后任何数据库写操作失败。
•DB_TRUNCATE:物理截断(空)包含数据库的磁盘上的文件。原因DB删除该文件中包含的所有数据库物理。
以下DB方法可能对你有用,当管理DB数据库:
•DB:: get_open_flags()返回当前打开标志。在未打开的数据上使用此方法,会返回错误。
#include <db_cxx.h>
...
Db db(NULL, 0);
u_int32_t open_flags;
// Database open and subsequent operations omitted forclarity
db.get_open_flags(&open_flags);
•Db::remove():删除指定的数据库。如果没有给定值的数据库中的参数,那么整个此方法所引用的文件被删除。
不要删除处于打开的数据库。切勿删除一个文件,如果该文件包含打开的句柄数据库。
#include <db_cxx.h>
...
Db db(NULL, 0);
// Database open and subsequent operations omitted forclarity
db.remove("mydb.db", // Database file to remove
NULL, // Databaseto remove. This is
// NULL so theentire file is
//removed.
0); // Flags. None used.
•Db::rename()
重命名指定的数据库。如果没有给定值的数据库参数,然后通过这种方法引用整个文件重新命名。切勿重命名一个打开处理的数据库。切勿重命名一个文件,如果其中包含打开的句柄数据库。
#include <db_cxx.h>
...
Db db(NULL, 0);
// Database open and subsequent operations omitted forclarity
db.rename("mydb.db", // Database file to rename
NULL, // Database to rename. This is
// NULL so theentire file is
// renamed.
"newdb.db", // New database file name
0); // Flags. None used.
为了简化错误报告和处理,DB类提供了几个有用的方法。
•set_error_stream()设置了C + + ostream的用于显示DB库输出错误消息。
•set_errcall()定义由DB发出一个错误消息时调用的函数。错误前缀和消息传递给这个回调。
•set_errfile()设置用于显示由DB库输出的错误消息的。
•set_errpfx()设置任何错误消息使用的前缀。
•ERR()问题的错误消息。该错误消息发送给回调函数所定义的set_errcall。如果该方法没有被使用,则错误消息被发送到由set_errfile()或set_error_stream()定义的文件。如果没有这些方法已被使用,那么错误信息会被发送到标准错误。
该错误消息由前缀字符串(如定义set_errpfx()),可选的printf风格的格式化消息,错误消息,和一个尾随的换行符。
•ERRX()行为与ERR()相同,除了DB附带的误差值关联的消息文本追加到错误字符串。此外,您可以使用的db_strerror()函数直接返回错误字符串对应一个特定的错误号码。例如,对于一个给定的数据库句柄回调处理所有的错误消息发送,首先要建立你的回调。做这样的事情:
/*
* Function calledto handle any database error messages
* issued by DB.
*/
void
my_error_handler(const char *error_prefix, char *msg)
{
/*
* Put your codeto handle the error prefix and error
* message here.Note that one or both of these parameters
* may be NULLdepending on how the error message is issued
* and how the DBhandle is configured.
*/
}
然后,注册的回调函数如下:
#include <db_cxx.h>
...
Db db(NULL, 0);
std::string dbFileName("my_db.db");
try
{
// Set up errorhandling for this database
db.set_errcall(my_error_handler);
db.set_errpfx("my_example_program");
发出错误消息:
// Open the database
db.open(NULL,dbFileName.c_str(), NULL, DB_BTREE, DB_CREATE, 0);
}
// Must catchboth DbException and std::exception
catch(DbException &e)
{
db.err(e.get_errno(), "Database open failed %s",
dbFileName.c_str());
throw e;
}
catch(std::exception &e)
{
// No DBerror number available, so use errx
db.errx("Error opening database: %s", e.what());
throw e;
}
要使用环境,你必须先打开它。在打开时,你必须确定它驻留的目录。此目录必须存在。还可以识别开放的属性,如环境是否可以创建,如果它已经不存在。
当你打开你的环境,您还需要初始化内存中缓存。
例如,要创造一种环境,处理和打开一个环境:
#include <db_cxx.h>
...
u_int32_t env_flags = DB_CREATE | // If the environment does not
// exist,create it.
DB_INIT_MPOOL; // Initialize the in-memory cache.
std::string envHome("/export1/testEnv");
DbEnv myEnv(0);
try {
myEnv.open(envHome.c_str(),env_flags, 0);
} catch(DbException &e) {
std::cerr<< "Error opening database environment: "
<< envHome << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
} catch(std::exception &e) {
std::cerr<< "Error opening database environment: "
<< envHome << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
}
一旦环境被打开,您可以打开数据库。请注意,默认情况下,数据库存储在环境的主目录,或相对于该目录,如果你提供任何形式的在数据库的文件名的路径:
#include <db_cxx.h>
...
u_int32_t env_flags = DB_CREATE; // If the environment does not
// exist,create it.
u_int32_tdb_flags = DB_CREATE; // If thedatabase does not
// exist,create it.
std::string envHome("/export1/testEnv");
std::stringdbName("mydb.db");
DbEnv myEnv(0);
Db *myDb;
try {
myEnv.open(envHome.c_str(), env_flags, 0);
myDb = new Db(&myEnv, 0);
myDb->open(NULL,
dbName.c_str(),
NULL,
DB_BTREE,
db_flags,
0);
} catch(DbException &e) {
std::cerr<< "Error opening database environment: "
<< envHome
<< " and database "
<< dbName << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
} catch(std::exception &e) {
std::cerr<< "Error opening database environment: "
<< envHome
<< " and database "
<< dbName << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
}
当你的环境,你必须关闭它时,确保您关闭所有打开的数据库。
try {
if (myDb !=NULL) {
myDb->close(0);
}
myEnv.close(0);
} catch(DbException &e) {
std::cerr<< "Error closing database environment: "
<< envHome
<< " or database "
<< dbName << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
} catch(std::exception &e) {
std::cerr<< "Error closing database environment: "
<< envHome
<< " or database "
<< dbName << std::endl;
std::cerr<< e.what() << std::endl;
exit( -1 );
}
在这本书中,我们将建立一个情侣的应用程序加载和检索库存数据从DB数据库。虽然我们还没有准备好,开始读取或写入到我们的数据库,我们至少可以创建这个类,我们将用它来管理我们的数据库。
请注意,随后在这本书中的例子将建立在执行这段代码从数据库写入和读取更有趣的工作。
请注意,你可以找到完整的执行这些功能:
DB_INSTALL/ examples_cxx/ getting_started
其中DB_INSTALL DB为安装位置。
例2.1 MYDB类
要管理我们的数据库打开和关闭的活动,我们把它们封装在MYDB类。有几个很好的理由这样做,最重要的是,我们可以确保我们的数据库被关闭MYDB类的析构函数中把该活动。
开始,我们创建的类的定义:
// File: MyDb.hpp
#include <db_cxx.h>
class MyDb
{
public:
// Constructorrequires a path to the database,
// and adatabase name.
MyDb(std::string &path, std::string &dbName);
// Ourdestructor just calls our private close method.
~MyDb() {close(); }
inline Db&getDb() {return db_;}
private:
Db db_;
std::stringdbFileName_;
u_int32_tcFlags_;
// Make surethe default constructor is private
// We don'twant it used.
MyDb() :db_(NULL, 0) {}
// We put ourdatabase close activity here.
// This iscalled from our destructor. In
// a morecomplicated example, we might want
// to make thismethod public, but a private
// method ismore appropriate for this example.
void close();
};
下一步,我们需要构造函数的实现:
// File: MyDb.cpp
#include "MyDb.hpp"
// Class constructor. Requires a path to the location
// where the database is located, and a database name
MyDb::MyDb(std::string &path, std::string&dbName)
: db_(NULL,0), // Instantiate Dbobject
dbFileName_(path + dbName), // Database file name
cFlags_(DB_CREATE) // Ifthe database doesn't yet exist,
// allow itto be created.
{
try
{
// Redirectdebugging information to std::cerr
db_.set_error_stream(&std::cerr);
// Open thedatabase
db_.open(NULL, dbFileName_.c_str(), NULL, DB_BTREE, cFlags_, 0);
}
// DbExceptionis not a subclass of std::exception, so we
// need tocatch them both.
catch(DbException &e)
{
std::cerr<< "Error opening database: " << dbFileName_ <<"\n";
std::cerr<< e.what() << std::endl;
}
catch(std::exception &e)
{
std::cerr<< "Error opening database: " << dbFileName_ <<"\n";
std::cerr<< e.what() << std::endl;
}
}
然后,我们需要close()方法的实现:
// Private member used to close a database. Called fromthe class
// destructor.
void
MyDb::close()
{
// Close the db
try
{
db_.close(0);
std::cout<< "Database " << dbFileName_
<< " is closed." << std::endl;
}
catch(DbException &e)
{
std::cerr<< "Error closing database: " << dbFileName_ <<"\n";
std::cerr<< e.what() << std::endl;
}
catch(std::exception &e)
{
std::cerr<< "Error closing database: " << dbFileName_ <<"\n";
std::cerr<< e.what() << std::endl;
}
}