[收藏]Berkeley DB文章集合--多库联合操作(Secondary Databases)

 
BerkeleyDB 多库联合操作 (Secondary Databases)
BerkeleyDB 多库联合操作 (Secondary Databases)
  
  BerkeleyDB
中,二级库( Secondary Databases )存在的意义在于:当我们在某一个库中对 key 值进行查询时,往往得不到我们想要的所有信息;又或者,我们想得到更多关于该 key 值对应的信息,而又不想进行过多的操作。比如说,在 database1 中,我们存储了 key 为员工 ID data 为员工籍贯、工资等信息,而 database2 中存储了 key 为员工名字, data 为员工 ID ,我们如果想要将几张表结合起来操作,就要涉及到对二级库的操作了。

 
二级库的打开 / 关闭与一般的库没有什么区别,所谓“二级库”“一级库( primary database )” , 只是在用 DB->associate() 函数将他们联系在一起的时候才具有他们字面上的意义。看下面一个代码片段:
  DB *dbp, *sdbp;
  db_create(&dbp, NULL, 0);
  db_create(&sdbp, NULL, 0);
  sdbp->set_flags(sdbp, DB_DUP); //
很多情况下,二级库需要支持 duplicate key
  dbp->open(
…… );   sdbp->open( …… );
  dbp->associate(dbp,         //
一级库句柄
  NULL,                       //TXN id
,这个还没整明白。。
  sdbp,                       //
二级库句柄
  callback_function,           //
回调函数有,后面会详细说明
  0);                         //
标志位
  sdbp->close();
  dbp->close();
 
注意:关闭库的时候,应该先关闭二级库,再关闭一级库。
 
  dbp->associate()
的原型为:
  DB->associate(DB *primary, DB_TXN *txnid, DB *secondary, int (*callback)(DB *secondary, const DBT *key, const DBT *data, DBT *result), u_int32_t flags);

 
当一个库被该函数声明为另一个库的二级库时 , 所以对一级库的操作将反映到二级库上 , 而对二级库记录的读操作返回的将是一级库相关记录的信息 . 注意 : 一级库的 key 值对于二级库来说应该是惟一的 , 所以不可以支持 duplicate key.

 
参数四为用来定义二级 key 值与一级 key data 值关系的回调函数,其四个参数分别为二级库句柄、一级库的 key/data 值、被创造的二级库 key 值。当两级库都是用 DB_READONLY 打开时,该参数可以设为空。
 
参数五可以为 0 或者 DB_CREATE DB_IMMUTABLE_KEY 之中的一个或两个 ( 按位与“ | ”上 ) DB_CREATE 是当二级库为空时使用,但开销较大,建议不要使用; DB_IMMUTABLE_KEY 指定返回的二级 key 为不可变,但注意当两级库以这个标志 associate 在一起的时候,由于二级库不变,改变与该二级 key 值相关的记录会造成两级的库不同步。

 
将一二级库联系在一起后,用 DB->get() DB->pget() 对二级库进行查找,但返回的 key/value 值为一级库中的记录。下面为普通读取的例子:
  sdbp->get(my_secondary_database, NULL, &key, &pdata, 0);
  sdbp->pget(my_secondary_database, NULL, &key, &pkey, &pdata, 0);  
 
注意: key 值的类型应该与 dbp->associate() 中回调函数中对 key 值定义的类型一致。
 
 
在很多情况下,二级库一般都是 duplicate key 支持的,所以,如果想要对某 key 值对应的 duplicate 列表全部进行操作的话,应该用游标的方法:
  while
cursor->c_get(cursorp, &key, &data, DB_SET) == 0) {
    cursor->c_del(cursorp, 0);
  }
 
删除所有相关库中所有与当前 key 值相关的记录。删除某二级库的记录会将一级库及其它所有关联起来的二级库的相关记录全部删除。注意:当你对二级库调用 DB->del (),如果该库支持 duplicate key 则该 key 对应 duplicate 列表将被全部删除。

另外也可以:
  sec_dbp->del(sec_dbp, NULL, &key, 0);
 
这样,如果该 key 值相关记录在某库中为 duplicate 形式的话,就只删除了 duplicate 列表的第一项。
 
下面我就 F2AS 系统中对于控制单元库( ctrl_unit db )与设备库 (device db) 的联合操作来具体说明:
ctrl_unit db
结构:
  key
long license    
  data
struct unit_db{char unit_id; char unit_addr; char name[20]; char producer[20];char product_date[20]; char install_date[20]; char install_place[20]; int area_num; int place_num; char project_num[20]; unsigned long ctrl_id }

device db
结构:
  key
unsigned long ctrl_id
  data
struct device{ char unit_id; char unit_addr; char name[20]; char producer[20]; char product_date[20]; char install_date[20]; char install_place[20]; int area_num; int place_num; char project_num[20]}

 
我们先分析一下两个库的联系: device db 中记录的 key 值与 ctrl_unit db 中记录的 data 结构中最后一个成员 ctrl_id 一致。这样,我们需要在对 device db 进行操作的同时对 ctrl_unit db 进行操作,所以我们将 device db 作为二级库, ctrl_unit db 作为一级库。所有出错处理省略。
 
  DB *ctrl_unit, *device;
  DBT key, pvalue, pkey;
  DBC *cursor;

  /***************
创建库 ***************/                
  db_create(&ctrl_unit, NULL, 0);
  db_create(&device, NULL, 0);

  /****
ctrl_unit 库支持 duplicate key*****/
  device->set_flags(device, DB_DUPSORT);  

  /************
打开库 *************/
  ctrl_unit->open(ctrl_unit, NULL,
ctrl_unit.db , NULL, DB_BTREE, DB_CREATE, 0);
  device->open(device, NULL,
device.db , NULL,DB_BTREE,DB_CREATE,0);
  device->cursor(device, NULL , &cursor, 0); //

  /************
关联库 , 参数四回调函数 get_ctrl_id 在后面定义 *********/
  ctrl_unit->associate(ctrl_unit, NULL, device, get_ctrl_id, 0); //ctrl_unit
作为一级库

  /*************
通过对二级库 device 游标的操作来操作一级库 ************/
  memset(key, 0, sizeof(DBT));
  memset(pkey, 0, sizeof(DBT));
  memset(pvalue, 0, sizeof(DBT));

  key.data = 10011; //
编号为 10011 的设备的记录
  key.size = sizeof(unsigned long int);
 
  unsigned long id;
  struct device dvc;
 
  pkey.data = &id;
  pkey.size = sizeof(unsigned long);
  pvalue.data = &dvc;
  pvalue.size = sizeof(struct device);

  cursor->c_get(cursor, &key, &pvalue, DB_SET);//
返回 ctrl_unit value
  cursor->c_pget(cursor, &key, &pkey, &pvalue, DB_SET);//
返回 ctrl_unit key,value 对。

  /*************
删除记录,这里假设 device 库支持 duplicate key**********/
  while(cursor->c_pget(cursor, &key, &pkey, &pvalue, DB_NEXT_DUP) == 0)
  {
    cursor->c_del(cursor, 0); //
将所有关联起来的库的该记录全部删除。
  }
 
while 语句其实等同于: device->del(device, NULL, &key, 0);

  /************
关闭游标,关闭库 ( 先二级,再一级 )*****************/
  cursor->close(&cursor);
  device->close(&device);
  ctrl_unit->close(&ctrl_unit);
  /*****************
主函数完 **********************/

  /*****************
主函数中 associate 所用回调函数 ***************/
  int get_ctrl_id (DB device, DBT pkey, DBT pvalue, DBT key)
  {
    struct unit_db *temp;
    temp = pvalue->data;
   
    memset(key, 0, sizeof(DBT));
    key->data = &(temp->ctrl_id);
    key->size = sizeof(unsigned long int);
    return 0;
  }

 
这样,就将一级库 ctrl_unit 记录的 value ctrl_id 项与二级库记录的 key 值关联了起来,当对二级库进行检索时,会自动找到一级库中 value.data.ctrl_id 与指定 key.data 相同的值。比如:二级库的 key.data = 1023 ,那么对二级库调用 DB->get (), DB->pget ()以及二级库游标操作的 DBC->get (), DBC-> pget ()将检索到一级库中相关记录。

 
注意:当要修改二级库的 key 值时,只需要直接修改一级库的关联项即可 , 所有相关二级库记录都将被修改。

 
在相关的表更多的情况下,我们还要涉及到“库集合”( Database Joins )的处理。对其的操作如下:
 
首先,打开所有相关一、二级库,并得到所有被关联的二级库的游标,再将他们指向各自库中你感兴趣的记录。
 
然后,将得到的游标存入一个游标数组,该数组最后一个参数为 NULL
 
接着用 DB->join() 将二级库与一级库组合,同时得到组合库的游标。函数原型如下:
  int DB->join(DB *primary, DBC **curslist, DBC **dbcp, u_int32_t flags);    
参数 1 为一级库句柄,参数 2 为游标数组,参数 3 为组合库的游标,参数 4 为标志(可以为 0 或者 DB_JOIN_NOSORT )。
 
再来就可以用组合库的游标进行操作 , 比如: DBC->c_get()
 
最后关闭所有库,先二级库再一级库。
 
看一个代码片段:
  DBC *color_curs = NULL, *make_curs = NULL, *type_curs = NULL, *join_curs = NULL;
  DBC *carray[4];
  DBT key, data;
   
  /****
打开库、打开游标、对 key data 赋值代码省略 ***/
  color_curs->c_get(color_curs, &key, &data, DB_SET)

  make_curs->c_get(make_curs, &key, &data, DB_SET)

  type_curs->c_get(type_curs, &key, &data, DB_SET);
  carray[0] = color_curs;
  carray[1] = make_curs;
  carray[2] = type_curs;
  carray[3] = NULL;
  dbp->join(dbp, carray, &join_curs, 0); //dbp
为一级库句柄。
  join_curs->c_get(join_curs, &key, &data, 0);
  /******
关闭库代码省略 ******/
 
 
最后要提的是,几个库的记录的结构应该能够关联起来,对于上面的代码来说:
  colorDB     key:
颜色   data :车牌号
  makeDB     key:
厂家   data :车牌号 
  typeDB     key:
品牌   data :车牌号
  carDB     key:
车牌号   data :汽车信息
 
大家注意二级库与一级库之间 key value 的形式的关系
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值