第六章 数据库
信息的恒久保存,对任何必须处理历史数据的应用程序都是至关重要的。两种方法:
1. 内置的数据库引擎。在应用程序中包含一个内置的数据库引擎,简单的持久性数据功能,而不用承担新服务器。
2. 利用全功能的开放源码数据库服务器。支持网络访问数据的服务器。
6.1 持久性数据存储
标准的文件读写/内置的数据库引擎/外部的数据库服务器,这是三种实现持久性数据存储的方法。
6.1.1 使用标准文件
打开文件、写入数据、读取数据、关闭文件标准流程----fopen(),write() ,read() ,fclose()
优点当然是简单啦,而缺点也显而易见,就是性能。在文件中查找数据是一个很大的挑战。
6.1.2 使用数据库
基于唯一的关键字来对数据进行排序有利于数据库快速低检索存储的信息,这比扫描每一个记录以发现需要的数据要快得多。
一个流派的想法是在应用程序里部署简单的数据库功能,例如db_create(),DB->put(), DB->get(), db_close()等。而另一个流派的想法是部署单独的数据库服务器,通过SQL语言用来对数据库服务器发送命令和检索结果。Standard Query Language,标准查询语言。
Berkeley DB展示了第一种流派,即加入内置数据库引擎的办法,而PostgreSQL则是建立中央服务器的解决方案。
6.2 Berkeley DB软件包
最受欢迎的和最有用的内置数据库引擎软件包,该数据库可以连接到C/C++应用程序之上。
历史:最开始时作为一个简单的数据库项目用于美国加州大学伯克利分校的BSD操作系统4.4版,1996年netscape公司希望作者发布一个通用的产品并单独成立了一个Sleeyycat软件公司对从BSD UNIX发行版中剥离出来的Berkeley DB软件进行开发。而此公司之后被oracle公司收购。oracle公司负责对Berkeley DB开放源代码产品进行维护。
地址:http://www.oracle.com/technology/products/berkeley-db/index.html
基本数据处理
links是一个命令行下的浏览器,可以用它来看命令行下的doc手册
dpkg -L "pkgname"可以列举出已经安装包的位置信息。
1. 打开和创建数据库
使用一个DB句柄来控制对数据库文件的访问,句柄通过db_create()创建
int db_create(DB **dbp, DB_ENV *env, u_int32_t flags)
dbp 指定访问数据库文件的DB句柄。env指定数据库文件打开时所处的环境。NULL代表一个独立的数据库,并且所有指定的设置只用于该文件。flags设置为0。成功返回0,失败返回非0值。
/* open the database */ ret = dbp->open(dbp, /* DB structure pointer */ NULL, /* Transaction pointer */ "my_db.db", /* On-disk file that holds the database. */ NULL, /* Optional logical database name */ DB_BTREE, /* Database access method */ flags, /* Open flags */ 0); /* File mode (using defaults) */ if (ret != 0) { /* Error handling goes here */ }
open方法int DB->open(DB *db, DB_TXN *txnid, const char *file, const char *database, DBTYPE type, u_int32_t flags, int mode)
如果函数调用属于一个事务处理的一部分,那么参数txnid指定一个打开的事务对象。file:文件名 database: 存储在该文件中的数据库的名字。允许在一个物理文件中存储多个数据库。type:数据库类型, DB_BTREE, DB_HASH, DB_QUEUE, DB_RECNO,不同的数据存储方式 flags: 数据库文件打开的方式.mode: Unix系统文件的格式.
ret = db_create(&dbp, NULL, 0); if (ret != 0) { perror("create"); return 1; } ret = dbp->open(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0); if (ret != 0) { perror("open: "); return 1; }
2. 新数据的添加
ret = my_database->put(my_database, NULL, &key, &data, DB_NOOVERWRITE); if (ret == DB_KEYEXIST) { my_database->err(my_database, ret, "Put failed because key %f already exists", money); }
int DB->put(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags)
DBT结构包含一个data成员和一个size成员。key.data包含记录的关键字值,而成员data.data包含记录的数据值。flags指定新数据放入数据库文件的方式。
DB_QUEUE/DB_RECNO ,使用DB_APPEND将记录添加到数据库文件的结尾.
DB_BTREE/DB_HASH则可以使用DB_NODUPDATA来保证不会向数据库中添加关键字/数据对相同的记录。
DB_NOOVERWRITE用来阻止关键字相同的记录。
下面展示了一条记录的写入过程:
memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); key.data = &(emp.empid); key.size = sizeof(emp.empid); data.data = &emp; data.size = sizeof(emp); ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE); if (ret != 0) { printf("Employee ID exists\n"); } }
key值:雇员的ID,data值:整个emp结构。注意跳出循环的判断条件。
3. 检索数据
ret = dbp->get(dbp, NULL, &key, &data, 0); if (ret != 0) { printf("Employee ID does not exist\n"); } else { printf(" Employee: %d - %s,%s\n", emp.empid, emp.lastname, emp.firstname); printf(" Salary: $%.2lf\n", emp.salary); } }
int DB->get(DB *db, DB_TXN *txnid, DBT *key, DBT *data, u_int32_t flags);
flags可以使用的值可以参考doc里的内容。
涉及到大量数据的存储和查询过程的时候,可以使用DB。似乎觉得这部分和自己做的没太大关系?