嵌入式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”或“扫一扫”下面二维码关注公众号,获取更多精彩内容。

请点击此处输入图片描述



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

架构师技术联盟(Hardy)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值