有了这些作为背景后,我们返回到次索引的讨论。因为 Berkeley DB 不了解键/数据对中数据元素的模式和结构,所以需要应用程序的帮助来找到我们用作次索引的字段。应用程序以回调函数方式提供帮助。回调函数接受键/数据对输入并返回引用了用作次键的值的 DBT。
所以要创建 last_name 的次索引,必须编写一个回调函数,接受键/数据对输入并返回引用了数据项的 last_name 字段的 DBT。
|
int lname_callback(DB *dbp, const DBT *key, const DBT *data, DBT *skey) { emp_data *edata; /* * We know that the opaque byte-string represented by the data DBT * represents one of our emp_data structures, so let's cast it * to one of those so that we can manipulate it. */ edata = data->data; skey->data = edata->lname; skey->size = strlen((edata->lname); return (0); } |
写完回调函数后,可以指定次索引。次索引只是一个表,所以先创建一个表:
|
DB *sdbp; ASSERT(db_create(&sdbp, dbenv, 0) == 0); /* Configure sdbp. */ ASSERT(sdbp->open(sdbp, NULL, "emp_lname.db", NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, 0644) == 0); |
再次使用 B 树结构对姓进行索引,保留以前使用的所有标记和模式。
最后,您必须将次索引表与主表(员工表)相关联。请记住,dbp 是员工表的句柄, sdbp 是次索引表的句柄。
ASSERT(dbp->associate(dbp, NULL, sdbp, lname_callback, flags) == 0);
注意事项:
· 可以了创建任意多的次索引。重要的问题是次索引降低了插入的速度 (因为您必须为每个次索引创建索引项),但如果使用次键值(如,姓)来查询和选择字节组, 它们将大大改进查询的性能。
· 在任何时候更新主表时,只要打开并关联了次索引,次索引将始终保持最新。但如果忘记打开并关联次索引,然后更改基表,您会发现次索引不是最新的。
应当避免这一情况。
DDL 中的最后两个操作是丢弃命令:丢弃索引、表和数据库。
如同在 SQL 中丢弃索引和删除表一样,您也能在 Berkeley DB 中完成这些操作。在 SQL 中,您可以执行以下命令
DROP TABLE employee
或者
DROP INDEX lname
在 SQL 中丢弃一个表将丢弃与之关联的所有索引,在 Berkeley DB 中,您必须显式完成此任务。幸运的是,在 Berkeley DB 中丢弃表或索引是同样的操作。
移除表前,必须关闭表上的所有数据库句柄。关闭表容易;假设我们要丢弃员工数据库的次索引。先关闭次索引:
sdbp->close(sdbp, 0)
在发出数据库句柄的关闭命令后,不能再使用句柄。
关闭次索引表后,您可以使用 dbenv 句柄的 dbremove 方法将其移除:
|
DB_ENV *dbenv; ASSERT(dbenv->dbremove(dbenv, NULL, "emp_lname.db", NULL, DB_AUTO_COMMIT) == 0); |
可以使用同一调用顺序 (closing 和 dbremoving) 来丢弃表。
假设不想丢弃表,只想更改其名称。您也可完成这一操作。
与移除一样,首先要关闭表句柄:
dbp->close(dbp, 0);
现在您可以更改表名称:
|
DB_ENV *dbenv; ASSERT(dbenv->dbrename(dbenv, NULL, "employee.db", NULL, "newemp.db", DB_AUTO_COMMIT) == 0); |
最后,您可能想销毁数据库。在 SQL 中执行
DROP DATABASE personnel
这一命令在 Berkeley DB 中也有对应的命令。
首先,必须关闭环境:
ASSERT(dbenv->close(dbenv, 0) == 0);
与关闭表句柄一样,当关闭环境句柄后,将不能使用该句柄。所以,为了丢弃表,您需要创建一个新句柄,然后使用该句柄移除数据库(环境)。
|
ASSERT(db_env_create(&dbenv, 0) == 0); ASSERT(dbenv->remove(dbenv, "my_databases/personnel", 0) == 0); |
至此,我们完成了 SQL 的 DDL 到 Berkeley DB 的转换。接下来,我们将讨论如何完成 SQL DML 到 Berkeley DB 的转换。
在 Berkeley DB 中执行 SQL DML 操作
我们已经介绍了 SQL 的 DDL 和其在 Berkeley DB 中的实现,现在要将数据添加到数据库,讨论 SQL 的插入、更新和删除。
在 SQL 中使用插入语句将数据插入表:
|
INSERT INTO employees VALUES (00010002, "mouse", "mickey", 1000000.00, "Main Street", "Disney Land", "CA", 98765); |
SQL 插入都变成了数据库或游标句柄的 Berkeley DB“put”方法;我们先讨论数据库,然后再探讨游标。
假设您已经打开了一个表,有一个数据库句柄 dbp 引用了员工表。现在,雇佣 Mickey Mouse。
|
DB *dbp; DBT key_dbt, data_dbt; emp_data edata; emp_key ekey; /* Put the value into the employee key. */ ekey = 00010002; /* Initialize an emp_data structure. */ strcpy(edata.lname, "Mouse"); strcpy(edata.fname, "Mickey"); edata.salary = 1000000.00; strcpy(edata.street, "Main Street"); strcpy(edata.city, "Disney Land"); strcpy(edata.state, "CA"); edata.zip = 98765; /* Initialize DBTs */ memset(&key_dbt, 0, sizeof(key_dbt)); memset(&data_dbt, 0, sizeof(data_dbt)); /* Now, assign key and data values to DBTs. */ key->data = &ekey; key->size = sizeof(ekey); data->data = &edata; data->size = sizeof(edata); /* Finally, put the data into the database. */ ASSERT(dbp->put(dbp, NULL, &key_dbt, &data_dbt, DB_AUTO_COMMIT) == 0); |
请注意,如果已经有将任何次索引与员工表相关联(如在 SQL 中),则在插入时将自动对其进行更新。
现在,假设表中有些数据,您希望对这些数据进行更改。例如,要给 Mickey 涨工资!有多种完成方法。