内容简介:嵌入式SQLite数据库架构和设计
SQLite是一个开源的、内嵌式的关系型数据库。SQLite和Oracle和Access一样是文件型数据库,就是说,一个数据库就是一个文件,此数据库里可以建立很多的表,可以建立索引、触发器等等,但是它实际上得到的就是一个文件。SQLite数据库具有下面的特点:
-
(1)首先SQLite数据库服务器就在你的数据库应用程序中,其好处是不需要网络配置和管理,也不需要通过设置数据源访问数据库服务器。
-
(2)其次SQLite数据库的服务器和客户端运行在同一个进程中。这样可以减少网络访问的消耗,简化数据库管理,使你的程序部署起来更容易。
-
(3)再次SQLite在处理数据类型时与其它的数据库不同。区别在于它所支持的类型以及这些类型是如何存储、比较、强化(enforc)和指派(assign)。
SQLite的域完整性被称为域亲和性(affinity)。为了理解类型亲和性,你必须先要理解存储类和弱类型(manifesttyping)。SQLite有Integer、Real、Text、Blob和Null五个原始的数据类型,被称为存储类。存储类这个词表明了一个值在磁盘上存储的格式,其实就是类型或数据类型的同义词。
数据库SQLite的数据库架构
SQLite在架构上采用了模块的设计,它由公共接口、编译器系统、虚拟机和后端四个子系统组成。
1、接口(Interface)。 由SQLite C API组成,也就是说不管是程序、脚本语言还是库文件,最终都是通过它与SQLite交互的(我们通常用得较多的ODBC/JDBC最后也会转化为相应C API的调用)。
2、编译器(Compiler)。 在编译器中,分词器(Tokenizer)和分析器(Parser)对 SQL 进行语法检查,然后把它转化为底层能更方便处理的分层的数据结构---语法树,然后把语法树传给代码生成器(code generator)进行处理。而代码生成器根据它生成一种针对SQLite的汇编代码,最后由虚拟机执行。
3、虚拟机(Virtual Machine)。 架构中最核心的部分是虚拟机,或者叫做虚拟数据库引擎(Virtual Database Engine,VDBE)。它和 Java 虚拟机相似,解释执行字节代码。VDBE的字节代码由128个操作码(opcodes)构成,它们主要集中在数据库操作。它的每一条指令都用来完成特定的数据库操作(比如打开一个表的游标)或者为这些操作栈空间的准备(比如压入参数)。
4、后端(Back-End)。 后端由B-树(B-tree),页缓存(page cache,pager)和操作系统接口(即系统调用)构成。B-tree和page cache共同对数据进行管理。B-tree的主要功能就是索引,它维护着各个页面之间的复杂的关系,便于快速找到所需数据。而pager的主要作用就是通过OS接口在B-tree和Disk之间传递页面。
嵌入式数据库SQLite的数据类型
在SQLite数据库中,不仅提供了储存基本数据的功能,而且提供了对二进制数据存储的能力,这样可以确保把采集到的农业图像信息存放到数据库中,由数据库统一操作和管理,在SQLite数据库中提供的基本数据类型不但可以进行转化,还可以进行大小比较。数据类型如下:
-
(1)Integer整数值。有正负之分,它是由8个字节(Bytes)表示。SQLite数据库可以根据整数值的大小自动控制其所占字节的个数。
-
(2)Real实数类型。在SQLite由8个字节来表示。
-
(3)Text文本字符数据类型。用来保存文本信息。SQLite数据库支持多种字符编码类型,包括UTF-8和UTF-16。字符串的大小是没有限制的。
-
(4)Blob二进制数据对象类型。保存二进制数据,大小没有限制。
-
(5)Null空类型。一个具有NULL存储类型的值比所有其它类型值都小。SQLite数据库对Null完全支持。
SQLite 数据库本身一共有80多个API调用接口,功能简单的数据库程序用三个接口完成: sqlite3_open(),sqlite3_exec(), 和 sqlite3_close()。 要是想更好的控制数据库引擎,使用sqlite3_prepare()函数把SQL语句编译成字节码再通过sqlite3_step()函数来执行。在SQLite中,绝大多数接口提供了UTF-8和UTF-16两个版本,大多数接口成对出现。
此外,SQLite数据库中同时也提供了用户对API接口扩充的机制。SQLite的扩充API用来支持用户定义的函数、聚合和 排序 法。实现一个用户自定义的函数分为两步。首先,写句柄。句柄实现一些你想通过SQL完成的功能。然后,注册句柄。为它提供SQL名称、参数的数量和一个指向句柄的指针。
数据库控制和语句执行方式
从数据库打开开始,SQLite就要为sqlite3 *类型准备好内存,一直到数据库关闭整个过程。打开数据库时,这个类型的变量指向你将操作的数据库。SQLite数据库和大多数据库操作相同,其过程连接并打开数据库、处理事务和断开连接并关闭数据库构成:
1、连接并打开数据库。 每个SQLite数据库都存储在单独的操作系统文件中,数据库与文件一一对应。连接并打开数据库的接口调用为sqlite3_open(),它用来打开一个数据库文件,该数据库文件中可以包含许多个关系表。该接口调用成功返回SQLITE_OK。
数据库打开成功。SQLite还可以创建内存数据库。如果你使用:memory:或一个空字符串做数据库名,数据库将在RAM中创建。内存数据库将只能被创建它的连接所存取,不能与其它连接共享。另外,内存数据库只能存活于连接期间,一旦连接关闭,数据库就将从内存中被删除。
2、处理事务。 SQLite 是支持事务处理的。默认情况下,事务自动提交,也就是每一个SQL语句都在一个独立的事务下运行。任何SQL语句命令都在事务下执行。可以通过Begin、Commit和Rollback等命令手动提交事务。如开始、提交、回滚事务过程如下:
3、数据库SQL语句执行。 在SQLite数据库中执行事务最常用的接口是sqlite3_exec(),在这个函数中有指向sqlite3_exec()的回调函数的指针参数。例如做 insert 操作或做 delete 操作时,就没有必要使用回调,该函数指针可设为NULL。而当你做 select 时,就要使用该回调函数,因为 sqlite3 把数据查出来,得通过回调告诉你查出了什么数据。
数据库对SQL语句的执行方式在下一节详述,回调函数的形式为:
typedef int (*sqlite3_callback)(void*,int,char**, char**)。
在SQLite数据库中执行事务的接口也可以是sqlite3_get_table(),它返回一个表格化的结果集。不需要提供回调函数。
4、执行SQL语句。 SQL语句的执行过程由三个阶段完成,下面会详述。
5、格式化(动态构造)SQL语句 ,利用sqlite接口函数构造SQL语句,并调用相关接口执行语句。首先调用sqlite3_mprintf()或sqlite3_vprintf()格式化SQL语句,接着调用sqlite3_exec()执行语句,最后调用sqlite3_free()释放内存资源。也可以调用sqlite3_exec_printf()完成整个过程。
6、断开连接并关闭数据库。 前面如果用 sqlite3_open 开启了一个数据库,结尾时不要忘了还要关闭所有附加的数据库文件。SQLite提供接口为SQLite3_close()。
SQL语句的执行在SQLite数据库中分两种情况,预编译查询和封装查询。
预处理查询是SQLite执行所有SQL命令的方式,每一个阶段都关联于语句句柄的一种状态(prepared、active和finalized)。Pepared表示所有资源都已分配,对应接口函数为sqlite3_prepare(),语句已经可以执行但还没有执行。现在还没有申请锁,一直到调用sqlite3_step()时才会申请锁。Active状态开始于对sqlite3_step()的调用,此时语句正在被执行并拥有某种锁。Finalized意味着语句已经被关闭且所有相关资源已经被释放。
封装查询是预处理查询的封装。在使用上比较简单,允许你在单一的函数调用中执行SQL命令。一个函数是sqlite3_exec(),特别适合执行不需要返回数据的查询。为了让查询结果数据返回,必须实现回调函数,传递给sqlite3_exec()函数作为参数。另一个是sqlite3_get_table(),返回一个表格化的结果集。封装查询也可以格式化SQL语句之后再执行。
二进制数据的数据库处理技术
在农业信息采集嵌入式系统中,为了满足对采集信息有效地在数据库中储存、管理、查询和传输的要求,必须要对数据库处理的关键技术进行研究。这些技术包括:记录和字符串处理、字段处理、错误控制、操作控制和线程处理。
1、记录和字符串的处理是数据库中最常用的处理方式。 在前面也提到过sqlite3_exec()和sqlite3_get_table()函数是处理事务和执行SQL语句接口,区别在于sqlite3_exec()在处理记录,如执行SELECT时,要得到处理结果需提供回调函数。提供回调函数的作用就是当在执行完对记录的操作后,让回调函数按需要得到处理结果。字符串处理主要用在对SQL语句的格式化上,在SQLite数据库中常用接口为sqlite3_mprintf()或sqlite3_vprintf()。
2、字段处理是在记录操作的基础上进行的。 在SQLite中提供了以对字段操作的函数接口,其特点是sqlite3_column_开头。这些接口可以获得字段名称、字段的存储类型和字段的值等信息。如获得一个字段的名称、储存类型和声明类型的函数调用如下:
3、SQLite数据库预定义了许多错误代码宏以方便程序设计错误处理的应用。 很多API接口函数的返回类型是整形,这表示返回错误码,所以在接口调用中可以根据返回码进行错误处理,可以使用函数sqlite3_errmsg()获得附加的错误信息。
图像数据在sqlite数据库中是按照二进制形式存放的。 操作二进制数据需要用一个辅助的数据类型:sqlite3_stmt * 。它是一个已经把SQL语句进行了解析,并用sqlite自己标记记录的内部数据结构来表示的SQL语句。正因为这个结构已经被解析了,所以你可以往这个语句里插入二进制数据。
把二进制数据插到 sqlite3_stmt 结构的过程,必须用sqlite 提供的函数来插入。SQLite数据库提供了一种通配符机制用来表示SQL语句中不确定的字符值,这些通配符如?、aaa、nnn等。做这些通配符所代表的值在sqlite3_bind_开头的接口函数中被填充,在SQLite数据库中提供了很多以sqlite3_bind_开头的接口用来给SQL声明中的通配符赋值。
二进制数据的存储相对比较复杂一点,但从数据库对二进制数据的操作来看,主要分为数据写入和数据读出。
1、数据写入是指将二进制数据写到数据库中,让数据库统一管理保存。 在SQLite中,二进制数据时保存在Blob数据类型中的。数据的写入步骤是:创建数据库关系表,构造含有通配符的插入二进制数据的SQL语句,然后把该语句解析到sqlite3_stmt 结构中。如:
调用接口函数sqlite3_bind_blob()给SQL申明的通配符赋值,该函数第二个参数为通配符的索引号,从1开始,有多个通配符时,要多次调用该函数。第三个参数为二进制数据开始指针,第四个参数为二进制数据长度。
sqlite3_bind_blob( stat, 1, pdata, (int)(length_data), NULL );
之后,二进制数据存放到了SQL语句。现在需要调用sqlite3_step()把sqlite3_stmt 结构表示的SQL语句就被写到了数据库里。最后调用sqlite3_finalize()释放sqlite3_stmt 结构的内存。
2、数据的读出是把二进制数据从数据库按照记录读出的过程。 该过程在循环中完成,在农业信息采集系统中可以进行图像信息的显示和无线传输。准备sqlite3_stmt* 结构,然后把读数据库的SQL语句解析到sqlite3_stmt 结构中。
sqlite3_prepare( db, “select * from tab”, -1,&stat, 0 );
接着开始循环查询数据,sqlite3_step( )返回SQLITE_ROW表示记录没有结束,否则表示结束。在循环中可获取ID值、二进制数据、二进制数据长度和数据处理,之后释放sqlite3_stmt* 结构内存。
SQLite的特性还体现在它既是一个数据库,一个程序库,一个命令行工具,也是一个学习关系型数据库的很好的工具。确实有很多途径可以把它使用到内嵌环境、网站、操作系统服务、脚本语言和应用程序。对于 程序员 来说,SQLite就像一个数据传送带,提供了一种方便的将应用程序绑定的数据的方法。
第九届中国云计算大会赠送的 免费专业票 可在指定权益范围内参加专题论坛和主题演讲,如果您觉得不够过瘾,还可以“ 原文链接 ”通过本号专属链接购买单日通票和全场通票(团购)支持,参加更多专业精彩内容。
温馨提示: 请搜索“ICT_Architect”或“扫一扫”下面二维码关注公众号,获取更多精彩内容。
请点击此处输入图片描述
以上所述就是小编给大家介绍的《嵌入式SQLite数据库架构和设计》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。