|
摘要 首先,分析Linux下的常见数据库技术。然后,指出嵌入式系统开发中对数据库的需求特点,论述SQLite嵌入式数据库的体系结构和开发技术。最后,结合ARM Linux开发平台,讲述具体的实现方法。 关键词 嵌入式数据库 SQLite ARM Linux 引言 随着嵌入式系统的广泛应用和用户对数据处理和管理需求的不断提高,各种智能设备和数据库技术的紧密结合已经得到了各方面的重视。不久的将来嵌入式数据库将无处不在。纵观目前国际、国内嵌入式数据库的应用情况,目前基于嵌入式数据库应用的市场已经进入加速发展的阶段。 1Linux 下常见的数据库技术分析 基于Linux平台的数据库非常多,大型的商用数据库有Oracle、Sybase、Informix、Informix、IBM DB2等;中小型的更是不胜枚举,以下是常见的几种。 (1) PostgreSQL PostgreSQL是世界上最优秀的开放源码的数据库之一,是完全免费的数据库,不需要任何版权费用和购买费。因此,它是许多Linux发行版本的首选,例如:Redhat、TurboLinux都预装了PostgreSQL。 PostgreSQL兼容性很强,如果是SQL92兼容的,移植PostgreSQL非常简单和快捷。 (2) MySQL MySQL是多用户、多进程的SQL database server。MySQL包括一个server daemon(mysqld)和client programs与libraries的client/server实现工具;比较适合小而简单的数据库,对复杂的操作要求支持不是很好。MySQL的licensing policy:如果你是普通的最终用户,使用MySQL不需要付钱;但如果是直接或间接地出售MySQL的服务程序或相关产品,或是在一些客户端维护MySQL server并收取费用,或是在发行版中包括MySQL,就需要获得许可。 * 本课题是2003年河南省杰出人才创新基金项目(0321000300),获得了河南省科技厅的资金支持。 (3) mSQL(mini SQL) mSQL是一个单用户数据库管理系统。由于它的短小精悍,使其开发的应用系统特别受到互联网用户青睐。mSQL并非是完全的freeware,若是在大学中使用此一软件,或是为了学术研究与慈善等非营利性目的,才能免费得到使用权(free license),否则就得付费注册才能得到正式的版权。 (4) Berkeley DB Berkeley DB是一个开放源代码的嵌入式数据库管理系统,能够为应用程序提供高性能的数据管理服务。应用它,程序员只需要调用一些简单的API就可以完成对数据的访问和管理。与常用的数据库管理系统(如MySQL和Oracle等)有所不同,在Berkeley DB中并没有数据库服务器的概念。应用程序不需要事先同数据库服务建立起网络连接,而是通过内嵌在程序中的Berkeley DB函数库来完成对数据的保存、查询、修改和删除等操作。 (5) SQLite SQLite支持绝大多数标准的SQL92语句,采用单文件存放数据库,速度又比 MySQL快上1~2倍(官方的数据),存储量也不是问题。在操作语句上更类似关系型数据库的产品使用,非常方便。SQLite的版权允许无任何限制的应用,包括商业性的产品。在PHP5中已经集成了这个轻巧的嵌入式数据库产品。 2嵌入式开发对数据库的需求特点 在众多的数据库中,如何选择适用于嵌入式系统的数据库呢?嵌入式系统开发环境决定了其对数据库需求的特点。 (1) 适当的体积 嵌入式系统对于数据的存储与程序的运行一般都有较强的空间限制,所以适用于嵌入式系统使用的数据库首先应该有一个适当的体积。 (2) 较强的功能 嵌入式开发中有很多应用,用户需求决定了开发中需要有一个大小适中且功能齐备的数据库来实现对数据的管理。对开发人员来说,要求采用的数据库技术提供完备开发的文档而且易于开发。 (3) 开源的代码 作为产品的开发,开源的代码不仅可以减少产品的生产成本,更重要的是为产品的维护完善和稳定运行都提供了最为彻底的解决手段。 上面介绍的数据库技术中,Oracle、Sybase、Informix、IBM DB2等功能强大,系统体积庞大,要求付费使用,仅适用于作为大型商业数据库。MySQL在保持中等体积的情况下,提供了较为适用的功能已经成为中小规模数据库应用的首选,但商业应用也要收费,而且对于嵌入式开发来说空间占用仍然太大,目前还不适用。 mSQL是一种简化的SQL数据库,短小精悍,开发方便,适用于嵌入式开发;但mSQL只有30天的使用期限,并非完全的开源。 余下的开放源码数据库中,PostgreSQL是Linux下最完善的开源SQL数据库,但体积也较大。Berkeley DB作为完全开源的嵌入式数据库速度极快,可靠性高;但学习起来有一定难度,必然会加大开发成本。 SQLite则简单易用,速度也很快,同时提供了丰富的数据库接口,功能虽较Berkeley DB略有逊色,但在开源社区的推动下差距正在缩小。它的设计思想是小型、快速和最小化的管理。这对于需要一个数据库用于存储数据,但又不想花太多时间来调整数据性能的开发人员很适用。实际上在很多情况下,并不需要存储程序或复杂的表之间的关联。这时会发现SQLite在大小和功能之间找到了一个理想的平衡点。完全的开源代码使其可以称得上是理想的“嵌入式数据库”。 3SQLite的体系结构及开发技术 SQLite是D·理查德·希普开发出来的用一个小型C库实现的一种强有力的嵌入式关系数据库管理体制。它提供了对SQL92的大多数支持:支持多表和索引、事务、视图、触发和一系列的用户接口及驱动。 这个库有很强的内聚性,通过不到25 000行的ANSI C代码实现,而且可以自由地应用于任何目的甚至包括商业应用。此外它还是高速、有效和可升级的,可以运行于从ARM/ Linux到SPARC / Solaris的多种硬件平台。 3.1体系结构 图1SQLite体系结构SQLite 有一种优雅、 标准化的设计。它可以分成8个主要子系统,如图1所示,其中有一些相当接近于关系数据库管理。 在图1的顶层是标记处理器(tokenizer)和分析器(parser)。SQLite有自己高度优化的分析生成器(柠檬分析器),可以快速地生产出高效率的代码,而且依靠它新颖的设计对内存泄漏有着特别的抵抗力。 在底部是基于Knuth经过优化的B树。这样可以运行在可调整的页面缓冲(page cache)上,有助于将对磁盘的查找减到最小。 再往下是页面高速缓存。它作用在OS的抽象层之上,这样的安排有助于数据库的移动。 体系结构的核心是虚拟数据库引擎(VDBE)。VDBE完成与数据操作相关的全部操作并且是客户和储存之间信息进行交换的中间单元。从各个方面来看,它都是SQLite的核心。在SQL语句被分析之后,VDBE开始起作用。代码生成器将分析树翻译成一个袖珍程序,随后这些袖珍程序又被组合成用VDBE的虚拟机器语言表示的一系列指令。如此往复,VDBE执行每条指令,最终完成SQL语句指定的查询要求。 VDBE 的机器语言由围绕于数据库管理 128 个操作码(opcode)组成。对于打开表,查询索引、存储和删除记录和很多其他数据库操作都有对应的操作码。在VDBE里的每条指令由1个操作码和3个操作数(operand)组成。一些指令使用全部(3个)操作数;也有些可能一个也未使用。这完全取决于指令的性质。例如Open指令,用于打开一个表的指针,使用了全部(3个)操作数:第1个操作数(P1)包含指针的ID号。第2操作数(P2)指出表的根位置(或者表的首页位置);而第3个操作数则是表的名字。对于Rollback指令则根本不需要操作数。为了进行一次Rollback VDBE,仅需知道是否要做Rollback\[1\]。 3.2SQLite开发技术 SQLite的API极其易于使用,只需要三个用来执行SQL和获得数据的函数。它还是可以扩展的,允许程序员自定义函数然后以callback的形式集合进去。C语言API是脚本接口的基础,如已经发布的(Tcl接口)。开放源码团体已经扩展了众多的客户接口、适配器、驱动等,这就使得其他语言对SQLite的使用也成为可能。 使用C语言API只需要三步。首先,要提供文件名和访问模式用来调用sqlite _open()连接数据库。然后,执行一个callback函数,SQLite通过对每个记录执行callback函数获得从数据库那里得到的结果。最后,如果想执行一个SQL查询并获得一个callback函数的指针,可以调用sqlite_exec()。除此之外还需要错误代码检查。SQLite可以通过对一个主键声明它为INTEGER PRIMARY KEY成为能够自动增加的主键,实现自增字段。 SQLite还提供了存取二进制大对象(BLOBs)的方法,在线程安全、数据库管理、API的扩展等方面也都提供了强大方便的技术支持。 4SQLite在ARMLinux平台上的实现 SQLite嵌入式数据库提供了以源码发布的方式,要在众多的硬件平台进行移植,可以根据不同平台对源码进行交叉编译来实现。编译主要有以下几个步骤\[2\]: ① 到http://www.sqlite.org/的cvs中下载最新的源代码包,解压后将生成sqlite目录,另外新建并转到一个与sqlite目录平行的同级目录,如make目录。 ② 用“echo $PATH”命令查看PATH中是否已经包含交叉编译工具armlinuxgcc。 ③ 为了在ARMLinux下能正常运行sqlite,需要对sqlite/src/sqliteInt.h作一定的修改,以确保btree(B树)有正确的变量大小,如“ptr”和“char*”。不同体系结构的Linux,如x86和ARM,会有些差别。对于ARMLinux可以找到如下部分:# ifndef INTPTR_TYPE # if SQLITE_PTR_SZ==4 # define INTPTR_TYPE int # else # define INTPTR_TYPE long long # endif 在上面的代码前加上一句#define SQLITE_PTR_SZ 4 这样后面的“typedef INTPTR_TYPE ptr;”就是定义的“int”类型,而不是“long long”。 ④ 使用configure进行一些配置。修改sqlite目录下的configure,让configure不去检查交叉编译环境。由于篇幅有限不再详述。 ⑤ 修改Makefile文件。将代码行 BCC = armlinuxgccgO2改成BCC = gccgO2。另外,一般是以静态链接的形式将sqlite放到ARMLinux的硬件板上运行的,所以继续修改Makefile,找到标记为sqlite:的代码段,将其中的libsqlite.la改成.libs/libsqlite.a。做完上述修改,用make生成sqlite、libsqlite.a、libsqlite.so。为了减小执行文件大小可以用strip处理,去掉其中的调试信息。 ⑥ 在ARM板上运行sqlite。将sqlite拷贝到ARM板上,方法很多,需要根据具体的情况来选择。如ftp、cmdftp、wget等。将sqlite下载到ARM板的/tmp目录,因为此目录是可写的。修改权限并运行:chmod +wx sqlite ./sqlite test.sqlite 会出现sqlite> 如果一切正常,现在sqlite已经在ARMLinux下跑了起来,然后就可以基于此进行进一步的应用开发了。 5SQLite的应用开发 家庭网络中央控制器以ARM微处理器为中心建立硬件平台,对外通过宽带Ethernet、Modem与Internet连接,对内将家用电器通过内部无线局域网连接成一体,通过远程Web浏览器、本地触摸屏以及电话语音三种方式实现对家用电器的状态查询和控制。多样化的数据存储与管理需要有一个后台数据库来支撑,SQLite无疑是一个合适的选择。下面就其应用程序的编写方式作一个简单的介绍。 为了讲解方便,下面例程通过程序代码生成了数据库sysdb及其中的一个表格user,也可以用sqlite命令行或者sqlitebrowse等图形化工具建立数据库。#include <string.h> #include "sqlite.h" int callback( void *p_data, int num_fields, char **p_fields, char **p_col_names); main(){ FILE *inp_fp; int ret; int nrecs = 0; char *errmsg; sqlite *p_db; unsigned char *sqlcommand; unsigned char * sqlcreatedb; sqlcommand="select * from user ;" ; sqlcreatedb="create table user(id numeric, name text);"; /*建立数据库*/ if ((inp_fp = fopen("./sysdb", "r"))==NULL) { printf("Cannot find database file !\\n"); printf("Recover the database file ...\\n"); p_db=sqlite_open("./sysdb",0777,0); sqlite_exec(p_db,sqlcreatedb,0,0,0); printf("The database file have been recorvered!\\n"); sqlite_close(p_db); } /*打开数据库*/ sqlite* p_db=sqlite_open("./sysdb", 0777, 0); /*选择 user表中的所有记录. */ ret=sqlite_exec(p_db,sqlcommand,callback, &nrecs, errmsg); if(ret!=SQLITE_OK){ printf("Error on SELECT: %s.\\n", errmsg); } else{ printf("Retrieved %i records.\\n", nrecs); } /* 关闭数据库*/ sqlite_close(p_db); } int callback( void *p_data, int num_fields, char**p_fields, char **p_col_names){ int i; int *p_rn = (int*)p_data; (*p_rn)++; for(i=0; i < num_fields; i++){ printf("%s " p_fields\[i\]); } return 0; }然后利用sqlite.h、libsqlite.a、libsqlite.so,根据需要进行交叉编译即可。 上例仅是一个简单的程序段,可以根据需要构造自己的数据库和callback函数,用来实现具体的功能。支持SQLite的第三方极多,在项目实际开发中还针对QT利用qtsqliteplugin插件开发了图形程序,用以实现通过触摸屏的本地交互界面,利用移植的Web服务器编写了CGI程序,实现了B/S模式的远程访问。 6总结 在经过大量的分析对比之后,针对嵌入式系统开发的特点,从众多数据库发行版中选出非常适用的嵌入式数据库SQLite。在ARMLinux下完成了对SQLite的编译,并基于此在项目中作了进一步的开发工作。实践证明,SQLite能够出色地完成嵌入式系统中的数据库应用需求。 参考文献 1Michael Owens. Embedding an SQL Database with SQLite. Linux Journal, 20030601 2How To Compile. http://www.sqlite.org/ 3薛启康. Linux环境下的数据库. 中国计算机报, 2001总期号:1009
|