基于ARM-Linux的SQLite嵌入式数据库的研究

时间:2008-08-28

  引言

  随着嵌入式系统的广泛应用和用户对数据处理和管理需求的不断提高,各种智能设备和数据库技术的紧密结合已经得到了各方面的重视。不久的将来嵌入式数据库将无处不在。纵观目前国际、国内嵌入式数据库的应用情况,目前基于嵌入式数据库应用的市场已经进入加速发展的阶段。

  1 嵌入式数据库

  1.1 嵌入式数据库的设计

  嵌入式数据库系统是指支持某种特定计算模式或移动计算的数据库管理系统,它通常与操作系统和具体应用集成在一起,运行在智能型嵌入式设备或移动设备上。嵌入式数据库的使用是采用程序驱动,即由程序调用相应的API来实现数据的存取。具有体积小巧、快速高效、稳定可靠、可移植性等特点,非常适用于嵌入式环境下的数据管理.。

  嵌入式数据库的主要设计思想如下图1所示,在向上层应用提供标准的数据库接口的同时,摆脱传统数据库仅仅由软件驱动的束缚,根据嵌入式系统的实际情况用SOC技术同时实现硬件驱动。软件部分按SQL92标准实现SQL语句的解析,实现事务管理功能、数据同步机制、数据的备份和恢复,软件部分不关心数据的实际存储,用标准C实现,能同任何嵌入式操作系统内核一同编译,能支持各嵌入式操作系统的安装格式,由数据库硬件驱动专用芯片实现对实际数据的访问功能(存储器读写,I/O通讯,异构数据库接驳)。

  图1  嵌入式数据库驱动结构图

  1.2. 嵌入式数据库SQLite

  SQLite 是D. Richard Hipp 在2000年开发的一个小型嵌入式数据库。他是完全独立的,不具有外部依赖性,可以较为方便地应用于嵌入式系统中。其源代码完全开放,可以用于任何用途,包括商业目的。SQLite 虽然是个极端轻量级的关系数据库,却保留了数据库的大部分特征,他提供了对SQL92 标准的大多数支持:支持多表和索引、事务、视图、触发和一系列的用户接口及驱动。其主要特征如下::

  (1) 支持原子的、一致的、独立的和持久的(ACID) 事务特性,即使系统崩溃和掉电。

  (2) 零配置(Zero2configuration),无需安装和管理。

  (3) 一个完整的数据库存储在单一磁盘文件中。

  (4) 数据库文件可以在不同字节顺序的机器间自由共享。

  (5) 支持数据库大小至2 TB。

  (6) 字符串和二进制大对象(BLOBs) 的大小仅被有效内存限制。

  (7) 源码体积小,编译后低于250 kB。

  (8) 大部分的操作比关系型数据库引擎要快。

  (9) 简单易用的API。

  SQLite 由于小、快、简单、可靠,而且作者完全放弃版权,从他一发布出来,便深受欢迎。对于嵌人式环境,管理、执行、维护的简单化比企业数据库引擎提供的许多复杂应用更重要,因此SQLite 数据库是一个很好的选择。

  2 SQLite 内部结构及开发技术

  2. 1  SQLite 内部结构

  SQLite 采用模块化的设计,主要由4个部分组成:内核(Core)、SQL编译器( SQL Compiler)、后端(Backend)以及附件(Accessories)。内部结构如图2所示。

  图2  SQLite 的内部结构

  SQLite 的接口是一些已经编写好的C库,即使使用不同语言的API,在底层仍然使用C 库执行。SQL语句通过接口进入到高效的SQL编译器,由标记处理器( tokeni2zer)分解成柠檬分析器(par ser) 可以识别的各个标志符,然后由分析器重新组合标志符并调用代码生成器(code generator) 生成虚拟机器码,交由虚拟机( virtual machine)去执行,终完成SQL 语句指定的任务。虚拟机是SQLite 内部结构的,不仅完成与数据操作相关的全部操作,而且还是客户和存储之间信息进行交换的中间单元。数据库按照B树(B2t ree) 的形式存储在磁盘上,通过可调整的页面缓冲(pager) 获得对数据的快速查找和存储。为了方便移植,SQLite 使用一个抽象层接口(OS in2terface) 与不同操作系统进行对接。

  2. 2  SQLite 开发技术

  SQLite 本身提供了C 语言的API 接口,使得对数据库的操作十分简单,主要是对3个API 函数的调用。

  (1) 打开数据库

  int sqlite3 open (

  const char 3 filename , / 3 数据库文件名(U TF28) 3 /

  sqlite3 3 3 ppDb   / 3 输出SQLite 数据库句柄3 /

  ) ;

  (2) 执行SQL

  int sqlite3 exec (

  sqlite3 3 ,      / 3 已经打开的数据库句柄3 /

  const char 3 sql ,   / 3 要执行的SQL 语句3 /

  sqlite callback ,   / 3 回调函数3 /

  void 3 ,      / 3 回调函数的个参数3 /

  char 3 3 errmsg   / 3 错误信息返回3 /

  ) ;

  (3) 关闭数据库

  int sqlite3 close ( sqlite3 3 ) ;   / 3 参数就是打开时的结构体,即数据库句柄3 /

  其中,sglite3 exec ( ) 函数的第二个参数用来处理一条或多条SQL 语句,语句间必须用“;”号隔开。如果是查询(SEL ECT) 语句,查询结果的每一条记录都必须调用第三个参数的Callback 函数,第四个参数则为Callback 函数的个参数指针。如果不是查询语句,第三、四个参数为NULL。所有SQL 执行完毕后返回0,否则返回错误代码,可通过第五个参数值来查看详细错误信息。

  3 SQLite 在ARM-Linux 平台上的实现

  SQLite 嵌入式数据库提供了以源码发布的方式,要在众多的硬件平台进行移植,可以根据不同平台对源码进行交叉编译来实现。编译主要有以下几个步骤:

  ① 到http :/ / www. sqlite. org/ 的cvs中的源代码包,解压并根据需要进行适当的修改后将生成sqlite目录,另外新建并转到一个与sqlite目录平行的同级目录,如make目录。

  ②用“echo $PATH”命令查看PATH中是否已经包含交叉编译工具arm linux gcc。

  ③为了在ARM Linux下能正常运行sqlite,需要对sqlite/ src/ sqliteInt . h作一定的修改,以确保bt ree (B 树)有正确的变量大小,如“pt r”和“char 3 ”。不同体系结构的Linux,如x86 和ARM,会有些差别。对于ARM2Linux可以找到如下部分:

  # ifndef IN TPTR_ TYPE

  # if SQL ITE_PTR_SZ = = 4

  # define IN TPTR_ TYPE int

  # else

  # define IN TPTR_ TYPE long long

  # endif

  在上面的代码前加上一句

  # define SQL ITE_PTR_SZ 4

  这样后面的“typedef INTPTR_ TYPE pt r ;”就是定义的“int”类型,而不是“long long”。

  ④准备使用configure进行一些配置。请在sqlite目录下的configure中找到如下4处,并将他们注释掉,这样可以让configure不去检查你的交叉编译环境。

  ⑤修改Makefile文件。将代码行BCC = arm linux gcc g O2 改成BCC = gcc g O2 。另外,一般是以静态链接的形式将sqlite 放到ARM Linux 的硬件板上运行的,所以继续修改Makefile ,找到标记为sqlite :的代码段,将其中的libsqlite. la 改成. libs/ libsqlite. a 。做完上述修改,用make 生成sqlite 、libsqlite. a 、libsqlite. so 。为了减小执行文件大小可以用st rip 处理,去掉其中的调试信息。

  ⑥在ARM 板上运行sqlite。将sqlite 拷贝到ARM板上,方法很多,需要根据具体的情况来选择。如ftp 、cm2 dftp 、wget 等。将sqlite到ARM 板的/ tmp 目录,因为此目录是可写的。修改权限并运行:

  chmod + wx sqlite

  . / sqlite test . sqlite

  会出现

  sqlite >

  如果一切正常,现在sqlite已经在ARM Linux下跑了起来,然后就可以基于此进行进一步的应用开发了。

  4 SQLite 在ARM- Linux 系统中应用实例

  在基于Linux的媒体网络附属存储(media network attached storage,Media NAS)系统中,选用SQLite数据库作为NAS系统中媒体数据的存储数据库,使得数字媒体播放设备通过UPnP ( universal plug-and-play)协议对NAS上的媒体文件进行播放。该系统中用户浏览媒体文件的流程如下::

  (1)当用户浏览NAS系统中的媒体文件时,执行DatabaseOpen数据库打开操作。

  (2)接着查找当前的SQLite数据库表,得到媒体文件的路径,通过DatabaseExecute执行SQL 查询语句得到路径。

  (3)通过媒体文件的路径打开媒体文件,把媒体文件,通过UPnP网络发送出去。SQLite的特点决定了它与应用结合时的便捷性。作为数据的存储介质,SQLite文件被保存为一个普通的磁盘二进制文件,它无需一个服务器进程来提供服务,对SQLite数据文件的直接操作即可完成想要做的工作。结合应用需求,在应用层编写了一组对SQLite的API调用操作的简单封装,部分封装函数如下::

  DatabaseOpen                             ;调用SQLite_open打开数据库文件

  DatabaseClose                             ;调用SQLite_close关闭数据库

  DatabaseExecute                         ;执行SQL命令

  应用层的部分封装函数的实现代码如下::

  int DatabaseOpen ( struct DBObj3 db, const char3 dbName)

  {

  char3 pzErrMsg = NULL;

  structDB Info3 pDB info;     / /数据库文件指针

  if (NULL = = dbName)               return 1;

  pDBinfo = ( struct DB Info3 ) db - > priv;

  pDBinfo - > stConnect = ( struct sqlite3 ) sqlite_open ( dbName, 0777, &pzErrMsg) ;

  if ( NULL = = pDB info - > stConnect )

  {

  printf ( " db open error. \n" ) ;

  return 1;

  }

  return 0;

  }

  int DatabaseExecute ( struct DBObj3 db, const char3 szSQL)

  {

  char3 pErrMsg = NULL;

  int nErrorCode;

  struct DB Info3 pDBinfo;

  pDB info = ( structDB Info3 ) db —> priv;

  nErrorCode = sqlite_exec ( ( struct sqlite 3 )(pDBinfo - > stConnect) ,

  szSQL, NULL, NULL, &pErrMsg) ;

  return nErrorCode;

  }

  可以看出,各个封装函数是通过调用SQLite的API函数实现的。在基于Linux操作系统上使用SQLite,经测试嵌入式数据库响应迅速,运行稳定,用户基本感觉不到命令延迟,在浏览声音和图像媒体时流畅自然,充分验证了使用SQLite数据库的优越性。

  5 总结

  在经过大量的分析对比之后,针对嵌入式系统开发的特点,从众多数据库发行版中选出非常适用的嵌入式数据库SQLite。ARM-Linux下完成了对SQLite的编译,并基于此在项目中作了进一步的开发工作。实践证明,SQLite能够出色地完成嵌入式系统中的数据库应用需求。

      欢迎转载,信息来自维库电子市场网(www.dzsc.com


  
上一篇:控制,行灯,自藕变压器有什么区别
下一篇:什么是干式变压器?什么是油浸电力变压器?

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料