基础

0:Berkeley DB的子系统

1:存取管理子系统

为数据库创建和读写提供支持,它不包含事务

2:内存池管理子系统

对DB使用的共享缓冲区进行管理,

3:事务子系统

提供事务管理功能

4:锁子系统

存取管理子系统用锁子系统同步对数据库的读写,事务子系统通过锁子系统实现多个事务的并发控制

5:日志子系统

用来支持事务子系统对数据的恢复,保证数据的一致性

 

应用程序直接调用的是存取管理子系统和事务子系统,这两个系统调用下层的内存池,锁,日志子系统

如果程序只需要支持多线程多进程并发但不需要事务,则可以只用锁子系统,如果程序单用户访问,不需要事务,则可以不用事务和锁子系统,这样会获得最高的性能

 

1:4种访问存取方式

1:访问方式应该和存取方式对应

HASH和BTree:当记录号不是数据存储的主键时,采用这两种访问方式,对于小数据量,两者性能没有区别,当数据量增大,BTree需要更多的附加信息来完成操作,这会导致IO繁忙,所以大数据Hash性能更好,由于BTree的key是依次放置的,如果连续访问顺序的数据,可能BTree的性能更好

Queue和Recno:插入时key为空,插入后会将key返回

Queue:定长,记录号是固定的

Recno:不定长,记录号可以选择固定和不固定

2:BTree、Queue、Recno算法可以记录编号,编号基于1,获得方式为DB->get()或者用游标,指定标志DB_SET_RECNO,返回的DBT data是一个db_recno_t类型,db_recno_t是32位无符号数据,这表明最多存储40多亿条数据

3:BTree启用编号会影响性能,BTree的编号是不固定的,在Queue中当达到最大编号时编号变为1,返回错误EFBIG,在Recno中编号达到最大时返回错误

 

2:环境

1:支持多个数据库文件在同一环境中

2:为多进程多线程访问提供支持,在一个环境中,可以共享一些内存和锁

3:提供事务支持

4:复制支持

5:支持日志系统

 

3:异常
try
{
}
catch(DbException &e)
{
	e.get_errno();  //error no
	e.what();		//message
}
catch(std::exception &e)
{
}

可以通过DB_CXX_NO_EXCEPTIONS关闭异常,程序中通过返回值处理错误 

 

4:返回值

函数调用成功返回0,错误返回非0

 

5:基本操作
Db db(NULL,0);		//环境,是否抛出异常
db.open(NULL,"test.db",NULL,DB_BTREE,DB_CREATE,0);

string str="life";
int    nLife=1000;

Dbt key,value;
key.set_data((void*)(str.c_str()));
key.set_size(str.length());
value.set_data(&nLife);
value.set_size(sizeof(int));

if(db.put(NULL,&key,&value,DB_NOOVERWRITE)==DB_KEYEXIST)
{
	return 0;
}
db.close(0);

 

6:打开标志

DB_CREATE,DB_EXCL,DB_RDONLY,DB_TRUNCATE

 

7:管理
//获得打开标志
Db db(NULL,0);
...
u_int32_t flags;
db.get_open_flags(&flags);

//删除数据库
Db db(NULL,0);
db.remove("mydb.db",NULL,0);

//重命名数据库
Db db(NULL,0);
db.rename("old.db",NULL,"new.db",0);

8:错误处理
Db db(NULL,0);
db.set_error_stream()		
db.set_errcall()			//设置一个函数指针,在异常发生时回调此函数
db.set_errfile()			//异常发生时,将异常消息写入一个文件
db.set_errpfx()				//异常发生时,错误消息的前缀
db.err()					//在catch()中使用,构建一个错误消息,此消息将根据上面几个函数的
							//调用发送给回调函数,或者写入文件,或者给C++ ostream,如果都没有设置
							//将会发送C++标准异常,然后在exception &e中通过e.what()写出

 

9:环境
u_int32_t evnFlags=DB_CREATE|DB_INIT_MPOOL; //必须初始化内存
string str="/xx/xxx";						//必须指定路径
DbEvn evn(0);
evn.open(str.c_str(),evnFlags,0);
Db db(&evn,0);
...
evn.close(0);

10:Records

1:获取数据

Dbt t1(123,sizeof(int));
string str=(char *)t1.get_data();

2:数据库默认不支持重复键,写重复键默认为覆盖值,设置DB_NOOVERWRITE为不准覆盖值

int ret=db.put(NULL,&key,&data,DB_NOOVERWRITE);
if(ret==DB_KEYEXIST)
{

}

3:删除Records

db.del(NULL,&key,0);

 

11:持久化数据

事务能够保证数据被写回磁盘,如果不想用事务,则可以调用

db.sync()

事务开销巨大,在一个没有使用事务的数据库关闭时默认执行此函数,如果在调用Db::close()指定了DB_NOSYNC则不执行写回操作

如果你没有使用事务你的程序或者系统蹦了,你应该销毁此数据库或者调用Db::verify(),如果verify()没有把数据库调整正确,你应该使用命令行db_dump -r或者-R去拯救你的数据库

 

12:游标
//创建
Dbc *cur;
Db db(NULL,0);
db.cursor(NULL,&cur,0);

//正向遍历
Dbt key,data;
while(cur->get(&key,&data,DB_NEXT)==0)
{

}
//反向遍历
while(cur->get(&key,&data,DB_PREV)==0)
{
}

//查找特定数据,可以通过key,或者data,或者key和data的组合,或者部分查找
cur->get(&key,&data,DB_GET);
//当查找一个数据时,如果没有找到,会返回DB_NOTFOUND

//相关标志
//SET只关注key,Get会同时关注key和data
DB_SET			//游标跳转到key相同的第一条记录
DB_SET_RANGE	//只能在BTree模式下使用,跳转到Key大于或等于的第一条记录,如果自己不提供比较函数,则会使用默认比较函数
DB_GET_BOTH
DB_GET_BOTH_RANGE


//关闭
cur->close();

 

13:游标访问Duplicate Records

1:Duplicate只会出现在BTree和Hash中,如果使用Db::del()删除一个key,这个set将会被全部删除,如果只想删除其中一个就应该使用游标

2:参数

DB_NEXT_NODUP

DB_PREV_NODUP

DB_NEXT_DUP  //没有返回DB_NOFOUND

 

14:使用游标插入数据

使用cur->put();

1:DB_NODUPDATA

如果数据库中已经存在相同的key,插入操作返回DB_KEYEXIST

如果为数据库提供了比较函数,则会插入到相应位置,如果没有提供,对于BTree会使用默认排序函数

想要使用此标志必须在创建数据库的时指定DB_DUPSORT

2:DB_KEYFIRST

如果数据库不支持Duplicate,插入操作会以默认的方式进行

如果数据库支持Duplicate并且提供了排序函数,会插入到其应该的位置

如果数据库支持Duplicate并且没有提供排序函数和已经存在了一个key值的记录,则他会插到此记录最前面

3:DB_KEYLAST

和DB_KEYFIRST基本一样,唯一的差别是如果没有提供排序函数,则会将Record插入末尾

 

15:使用游标删除数据和覆盖数据

cur->del(0);

cur->put(&key,&value,DB_CURRENT);   //你不能覆盖key,如果你指定了key,其实是无效的

如果数据库支持重复记录,你覆盖的记录是重复记录中的一条,只有你覆盖的数据和以前的数据排序是一样的,这次覆盖才会成功;特别的,如果你使用的是默认排序算法

如果你提供了排序算法,并且这个排序算法使用了data,想要执行覆盖重复记录很可能失败,替代办法是执行删除然后创建记录的操作

 

16:Secondary Databases

1:将第一个数据库key查询出的value通过fun函数计算后得到新的值作为第二个数据库的key,提供的函数返回0则代表插入此记录

Db dbPrimary(NULL,0);
Db bdSecondary(NULL,0);
dbPrimary.open(...);
bdSecondary.open(...);

dbPrimary.associate(NULL,&bdSecondary,fun,0);

2:关闭时应该先关闭二级数据库,再关闭一级数据库

3:如果想将fun计算后的值为多个,将这多个值作为key进行查询,则使用如下方式:

skey.set_flags(DB_DBT_MULTIPLE|DB_DBT_APPMALLOC);
skey.set_data(...);		//一个DBT的数组,数据中的元素内容必须是唯一的
skey.set_size(2);		//数组元素个数

4:获取Secondary Database的数据

如果一个数据库被associate到primary数据库,则当调用get()时,返回的是primary的value,如果使用pget(),返回的是primary的key和value

5:通过del()删除一个二级数据库的记录会导致primary数据库相应的记录被删除,如果你的二级数据库有支持dumplicate key,删除一个key会导致整个key相同的记录被删除

6:可以使用游标遍历二级数据库,返回的value是primary数据库的value

7:二级数据库不能增加,修改数据,但能删除数据

 

17:Join cursor

步骤:

1:创建多个二级数据库,附加到同一个一级数据库

2:为每个二级数据库创建一个游标

3:创建一个游标指针数组,放二级数据库的游标指针,最后一个数组元素为空

4:创建一个新的游标,调用一级数据库Db::join();

5:使用,删除

 

18:配置

1:page size

Db::set_pagesize();512bytes到64kb,一般设置为系统页面大小,此选项受四个方面的影响

(1):overflow页,当记录超出了页大小,会将超出的部分保存在overflow页中,由于overflow页是额外的页面,这会影响性能

(2):DB锁定是以此设置为单位,如果设置的太大,锁定的数据会更多,会影响并发性能

(3):DB页大小是系统页面大小的整数倍效率会最高

(4):使用事务时,页大小会影响数据库错误的恢复

2:chche size

Db::set_cachesize()或者Evn::set_cachesize(),你的缓存大小必须是2的平方,根据程序测试获得最佳的值

3:BTree configuration

(1):Db::set_bt_compare()  设置排序函数

(2):Db::set_dup_compare() 支持重复记录的排序函数,如果不提供此函数,put()操作会将记录插入到重复记录集的末尾,或者在put()是制定:DB_AFTER,DB_BEFORE,DB_KEYFIRST,DB_KEYLAST

(3):配置数据库支持重复记录:Db::set_flags():

a:DB_DUP 数据库支持不排序的重复记录

b:DB_DUPSORT 数据库支持排序的重复记录

4:几种情况下你可能会提供自己的排序函数而不是用默认的

1:对于你的本地语言,使用特殊的排序准则

2:如果你用int作为key,berkeley DB实际上都认为key是string,int是4个字节的string,当你传入一个key进行比较时,在小端口计算机系统上,由于高字节在前,会进行一些无谓的比较导致性能损失

3:为了性能考虑,你可能不想比较所有的字符,比如:只比较前五个字符,如果相等,就认为他们是相等的

 

19:杂项

1:BTree

Db::set_bt_compress(dbp,NULL,NULL), 后面两个NULL参数表示使用BDB自带的缺省压缩和解压缩算法,该函数需要在DB被打开之前调用

2:Hash

1. DB->set_h_ffactor()设置填充因子,用于确定每个hash bucket中可能容纳key/value的一个近似值,以决定hash table应该在什么时候增长或缩短.请参照以下设置方式
     (pagesize - 32) / (average_key_size + average_data_size + 8)
2. DB->set_h_hash(),设置自定义的hash方法
3. DB->set_h_nelem(),用于设定hash table中可能容纳的element数量,如果设置的比较接近真实情况,将更好的避免由于hash bucket动态增长而带来的性能损失,设置该值时也需要考虑设置fill factor

3:Queue

DB->set_re_len(),确定记录长度,短于该长度,用DB->set_re_pad()中的的字符填充,长于改长度产生错误

 

20:分区

1. 只用BTree和Hash两种方式可以支持partitioning。
2. DB->set_partition(),DB->set_partition_dirs(), 这两个函数用于对DB进行partition,他们必须在数据库第一次被open之前调用,一旦partition成功之后,其partition的scheme将不能再改变。其中后面的函数主要用于指定partition文件所在的home directory。分区策略是,可以给partition指定其所包含的key的值,也可以通过回调函数的方式,通过回调函数的返回值来确定该键应该存放的partition。
     a--f to go on partition 0
     g--p to go on partition 1
     q--z to go on partition 2

如果打算使用数组的方式进行partition,set_partition中回调函数参数为NULL。

1 void partition_exampe_with_array() {
2 DBT partKey[2];
3 int ret;
4 
5 memset(partKeys,0,sizeof(DBT) * 2);
6 partKeys[0].data = "g";
7 partKeys[0].size = sizeof("g") - 1;
8 partKeys[1].data = "q";
9 partKeys[1].size = sizeof("q") - 1;
10 
11 dbp->set_partition(dbp,3,partKeys,NULL);
12 }

如果打算使用回调的方式进行partition,set_partition中分区提示数组参数为NULL。

1 void partition_example_with_callback() {
2 dbp->set_partition(dbp,3,NULL,db_partition_fn);
3 }
4 
5 //参数key实际存放的partition No = ret % number_of_partitions
6   u_int32_t db_partition_fn(DB* db,DBT* key) {
7 char* key_data;
8 u_int32_t ret;
9 
10 key_data = (char*)key->data;
11 //根据key_data的值进行自定义运算,从而判定该key应该存放的partition。
12   ret = 0;
13 return ret;
14 }

3. DB->set_partition_dirs(),该函数必须在数据库创建和打开之前设定,一旦成功设定并打开DB,该值将不可变。推荐设置和partition相同数量的dirs。dir可以通过绝对和相对路径支出,可以位于不同的磁盘。如果DB的打开是基于Environment的,在设置之前,需要保证所设定目录已经存在于DB_ENV->add_data_dir()的列表中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值