嵌入式数据库
嵌入式数据库
一、数据库综述
数据库(DataBase,简记为DB)
是一个有 结构的 、 集成的 、 可共享的、统一管理的 数据集合。它不仅包括数据本身,而且包括相关数据之间的联系。数据库技术主要研究如何存储、使用和管理数据;
所谓有 结构 的,指的是数据是按一定的模型组织起来的。
数据模型可用数据结构来描述。
数据模型决定数据的组织方式、操作方法。
理解数据库的前提是理解数据模型。
现在的数据库多数是以关系模型来组织数据的。
可以简单地把关系模型的数据结构-关系理解成为一张二维表。
所谓 集成 的,是指数据库中集中存放着企业各种各样的数据。
集中存放的好处是:一个数据只需一个备份,重复存储少,即消除了数据的冗余。
没有数据冗余,也就能保证数据的一致。(题外:冗余能够提高数据可靠性)
所谓 共享 ,指的是数据库中的数据可以被不同的用户使用。也就是说,每一个用户可以按自己的要求访问相同的数据库。
所谓 统一管理 的,指的是数据库由DBMS统一管理,任何数据访问都是通过DBMS来完成的。
数据库管理系统(DataBase Management System,DBMS)
☆是用来管理数据库的一种商品化软件。
☆所有访问数据库的请求都由DBMS来完成的。
☆DBMS提供了操作数据库的许多命令(语言),即SQL语言。
数据库管理系统的层次结构
根据处理对象的不同, 数据库管理系统的层次结构由高级到低级依次为应用层、语言翻译处理层、数据存取层、数据存储层、操作系统。
常见的关系型数据库管理系统:
目前有许多数据库产品,如Oracle、SQL Server、DB2、MySQL 、Access,SQLite3等产品各以自己特有的功能,在数据库市场上占有一席之地。
二、数据库基础知识
数据管理技术的发展过程
人工管理阶段(40年代中–50年代中)
文件系统阶段(50年代末–60年代中)
数据库系统阶段(60年代末–现在)
数据库特点
数据模型
数据模型的组成要素 (1) 数据结构 (2) 数据操作 (3) 数据的完整性约束
数据模型: 层次数据模型、网状数据模型、关系数据模型、面向对象数据库模型
层次模型 按树型结构组织数据,它是以记录类型为结点,以结点间联系为边的有序树,数据结构为有序树或森林。
优点: 数据结构很类似于金字塔,不同层次之间的关联性直接而且简单。
缺点: 由于数据纵向发展,横向关系难以建立,数据可能会重复出现,造成管理维护的不便。
网状模型 用网状结构表示实体及其之间的联系,网中结点之间的联系不受层次限制,可以任意发生联系。
优点: 避免了数据的重复性,具有良好的性能,存取效率高。
缺点: 关联性比较复杂,尤其是当数据库变得越来越大时,关联性的维护会非常麻烦。
关系型数据库模型
用关系(二维表格形式结构)来表示实体类型以及实体间联系的模型称为关系模型。关系数据模型是由IBM公司的E.F.Codd于1970年首次提出,以关系数据模型为基础的数据库管理系统,称为关系数据库系统(RDBMS),目前广泛使用。
面向对象数据库模型:
使用面向对象技术(Object-Oriented,简称OO)来表示信息世界的实体类型及实体之间联系的模型称为对象模型。
数据库系统的三级模式结构
☆ 数据库系统的 三级模式结构 是指数据库系统是由 外模式 、 模式 和 内模式 三级组成。
外模式(External Schema) :
外模式也称 子模式或用户模式 ,它是数据库用户(包括应用程序员和最终用户)看见和使用的局部数据的逻辑结构和特征的描述,是数据库用户的数据视图,是与某一应用有关的数据的逻辑表示。 外模式一般是模式的子集。一个模式可以有多个外模式。一个应用程序只能使用一个外模式。外模式是保证数据库安全性的一个有力措施。
模式(Schema) :
模式也称为逻辑模式或概念模式,是数据库中 全体数据 的逻辑结构和特征的描述,是所有用户的公用数据视图。 一个数据库只有一个模式 。模式是数据项值的框架。数据库系统模式通常还包含有访问控制、保密定义、完整性检查等方面的内容。
内模式(internal Schema) :
内模式也称为存储模式,它是数据库在物理存储器上具体实现的描述,是数据在数据库内部的表示方法,也是数据物理结构和存储方式的描述。 一个数据库只有一个内模式。
二级映像功能与数据独立性
数据库系统在三级模式之间提供了两层映像:外模式/模式映像和模式/内模式映像。正是这两层映像保证了数据库系统的数据能够具有较高的逻辑独立性和物理独立性。
数据的逻辑独立性
模式描述的是数据的全局逻辑结构,外模式描述的是数据的局部逻辑结构。对应于同一个模式可以有任意多个外模式。对于每一个外模式,数据库系统都有一个外模式/模式映像,它定义了该外模式与模式之间的对应关系。当模式改变时(例如,增加新的数据类型、新的数据项、新的关系等),由数据库管理员对各个外模式/模式的映像作相应改变,可以使外模式保持不变,从而应用程序不必修改,保证了数据的逻辑独立性
数据的物理独立性
数据库中只有一个模式,也只有一个内模式,所以模式/内模式映像是惟一的,它定义了数据全局逻辑结构与存储结构之间的对应关系。当数据库的存储结构改变时(例如,采用了更先进的存储技术),由数据库管理员对模式/内模式映像作相应改变,可以使模式保持不变,从而保证了数据的物理独立性。
数据库系统结构
从数据库管理系统的角度,数据库系统通常采用三级模式结构,这是数据库管理系统内部的系统结构。从数据库最终用户的角度看,数据库结构分为集中式、分布式、客户/服务器和并行结构等。
单用户数据库系统
单用户数据库系统是一种早期的最简单的数据库系统。在这种系统中,整个数据库系统(包括应用程序、DBMS、数据)都装在一台计算机上,由一个用户独占,不同机器之间不能共享数据。
主从式结构
主从式结构是指一个主机带多个终端的多用户结构。在这种结构中,数据库系统(包括应用程序、DBMS、数据)都集中存放在主机上,所有处理任务都由主机来完成,各个用户通过主机的终端并发地存取数据库,共享数据资源。
分布式结构
指数据库中的数据在逻辑上是一个整体,但物理地分布在计算机网络的不同节点上。网络中的每个节点都可以独立处理本地数据库中的数据,执行局部应用;同时也可以同时存取和处理多个异地数据库中的数据,执行全局应用。
客户/服务器结构
在客户/服务器结构中, 客户端 的用户请求被传送到 服务器 ,服务器进行处理后,只将结果返回给用户(而不是整个数据),从而显著减少了网络上的数据传输量,提高了系统的性能、吞吐量和负载能力;另一方面,客户与服务器一般都能在不同的硬件和软件平台上运行,可以使用不同厂商的数据库应用开发工具,应用程序具有更强的可移植性,同时也可减少软件维护开销。
三、关系数据库理论
关系术语和定义
关系(Relation):一个关系就是一张二维表 ,每一个关系有一个关系名,可以存储为一个文件。其定义可以描述为 的子集叫做域 , ,…, 上的关系,表示为 , R 表示 关系的名称 , n 表示 关系的目或度(Degree) 。
元组: 表中的行称为元组, 一行就是一个元组 ,对应存储文件中的一个记录。
属性: 关系中的一列称为一个属性。 一个属性必须有唯一的属性名 , 一个关系可以有若干个属性值 。(题外:对列是数据的定义,对行是数据的操纵)
域(Domain) : 属性的取值范围 ,是一组具有相同数据类型的值的集合。
关系的候选键与主键
☆表中 某一列 (或若干列的最小组合)的值能 惟一标识一个行 ,称该列或列组为 候选键 。如Students表的学号列,就是一个候选键。
☆对于一个表,可能有多个候选键 。
☆候选键取决于应用范围,如给定条件,没有重复的学生姓名,则姓名是学生基本情况表的一个候选键。
☆如果一个表有多个候选键,数据库设计者通常选择其中一个候选键作为区分行的 惟一性标识符 ,称为主键(primary key,PK)。 如果一个表只有一个候选键,那么这个候选键就作为主键 。
例如,在学生基本情况表中,把学号作为该表的主键。
☆因为主键是候选键之一,而根据候选键的定义,候选键列上的各个值都惟一,因此 主键列上的各个值也都惟一
外键
外键(Foreign Key,FK):若一个表R1中的一个列或列组对应另一个表R2的主键,那么该列或列组称为表R1的外键。
外键可以由 一个或多个 列组成, 可以有重复值
四、嵌入式数据库综述
嵌入式存储需求
便捷信息存储和查询功能是系统软件必备的基本服务,嵌入式系统也不例外 关系数据库技术历经数十载的发展,相关概念深入人心,成为最重要的信息存储和检索手段。 相对现有的通用计算机系统,嵌入式系统运行环境要求苛刻,同时不同的系统对于性能要求也存在很大的不同
嵌入式数据库系统应用分类
高性能嵌入式系统
☆电信和网络设备 ☆航空航天 ☆工业自动化控制
高可靠性:通常通过备份,冗余等手段;
要求系统的分布式特性:分布式存储,分布式事务;
高性能:要求数据库系统的实时特性;
多平台的适应性;
多用内存数据库方式,采用非易失存储介质作为后备;
存储数据类型复杂;
中等嵌入式系统
☆车载电子,GPS ☆机器人
广泛的平台适应性:WCE,Linux, VxWorks 等等;
存储的数据类型复杂多变:多媒体数据,地理信息数据等等;
存储介质类型多样:内存,NAND/NOR FLASH, SD/MMC,微型磁盘等;
通常会有响应时间的要求;
要求接口简单,容易开发;
微嵌入式应用
☆个人数字助理(PDA)
☆智能手机
对于资源使用有一定限制,存储空间,处理能力等均受限(虽然对于某些高档机型这种限制并不大);
要求广泛的平台适应性:WCE,Linux等;
要求具有丰富的数据类型(多媒体数据,地理信息数据);
多样的存储设备:内存,NAND/NOR FLASH, SD/MMC,微型磁盘等;
对查询响应时间要求不高,满足人机交互的需求即可;
要求和外部数据库的同步能力(Data Sync)
微微嵌入式应用
☆智能卡
☆智能玩具
苛刻的运行环境:要求对资源的占用达到最小限度。
存储数据类型简单,数据量小。
嵌入式数据库的挑战
1、传统的RDBMS建立在以磁盘/磁鼓等DASD为存储介质的基础上的,而嵌入式系统常见的Flash Memory等存储介质和DASD在特性上有较大的不同,传统RDBMS的很多假设不再成立。
2、传统的RDBMS的优化策略建立在对系统资源的最小占用,提高系统的吞吐量,而嵌入式RDBMS面对着可能是非常不同的优化目标。
3、嵌入式RDBMS系统面临着苛刻的软/硬件运行环境,要求数据库结构上加以考虑。
4、嵌入式数据库运行环境和存储介质多种多样,用单一的体系结构做到“通吃”几乎是不可能。
嵌入式数据库的基本要求
体积适当
由于嵌入式系统自身的特点,对数据的存储和程序的运行都有较强的空间限制,所以嵌入式数据库首先应该保障的就是适当的体积。进一步来说就是占用尽量少的ROM、RAM及CPU的资源。
可移植性
嵌入式系统的平台种类繁多,因此嵌入式数据库应有一定的可移植性,以适用于不同的软硬件平台。特别是要考虑到不同存储介质的特性,比如NAND的读特性
编程接口简单
不必要提供完整的SQL和数据库连接方式。
代码开源
开源的代码在产品的开发过程中不仅可以减少开发成本,更重要的是为后期的维护完善和稳定运行都提供了最为彻底的解决方法。
五、linux中sql语法
创建数据库
sqlite3 test.db
create table test (id integer primary key, value text);
名为id的主键列:该列默认具备自动增长的属性;
名为value的简单文本域;
插入操作
insert into test (id,value) values(1,’zhang’);
insert into test (id,value) values(2,’wang’);
insert into test (value) values(‘liang’); (自动加入id值,3.4….)
insert into test (value) values(‘liang’);
查看数据:select * from test;
更改数据:update mytable set name = ’ling’ where name=‘liang’;
退出:sqlite> .exit
增加数据名:.head on
增加列宽:.mode column
删除操作:delete from mytable where id=2;
增加项:alter table mytable add column email text not null default ’ ‘;
语法
SQL的语法很像自然语言。 每个语句都是一个祈使句,以动词开头,表示所要做的动作。
命令
SQL由命令组成, 每个命令以分号(;)结束 。如下面是3个独立的命令:
SELECT id, name FROM foods;
INSERT INTO foods VALUES (NULL, ‘Whataburger’);
常量
也称为Literals,表示确切的值,有3种:字符串常量、数据常量和二进制常量。
字符串常量如:‘Jerry’ ‘Newman’ ‘JujyFruit’
数据常量:数字常量有整数、十进制数和科学记数法表示的数,如:-1 3.142 6.0221415E23
二进制值用如x'0000’的表示法,其中每个数据是一个16进制数。二进制值必须由两个两个的16进制数(8 bits)组成,如:x'01’ X'0fff’x'0F0EFF’
保留字和标识符
保留字由SQL保留用做特殊的用途,如SELECT UPDATE、INSERT、CREATE、DROP和BEGIN等。标识符指明数据库里的具体对象,如表或索引。保留字预定义,不能用做标识符。SQL不区分大小写,下面是相同的语句:
SELECT * from foo;
select * from foo;
创建数据库
创建表
在SQL中,创建和删除数据库对象的语句一般被称为数据定义语言(data definition language,DDL),操作这些对象中数据的语句称为数据操作语言(data manipulation language,DML)。创建表的语句属于DDL,用CREATE TABLE命令,如下定义:
CREATE [TEMP] TABLE table_name (column_definitions[, constraints]);
CREATE TABLE命令至少需要一个表名和一个字段名。命令中table_name表示表名,必须与其它所有的标识符不同。column_definitions表示一个用逗号分隔的字段列表。每个字段定义包括一个名称、一个域和一个逗号分隔的字段约束表。“域”一般情况下是一个类型,与编程语言中的数据类型同名,指明存储在该列的数据的类型。 在SQLite中有5种本地类型: INTEGER、REAL、TEXT、BLOB和NULL
改变表
你可以用ALTER TABLE命令改变表的结构。SQLite版的ALTER TABLE命令既可以改变表名,也可以增加字段。一般格式为:
ALTER TABLE table { RENAME TO name | ADD COLUMN column_def }
数据查询语句
SELECT是SQL命令中最大最复杂的命令。SELECT的很多操作都来源于关系代数。
select基本结构
SELECT <目标列名序列>
FROM <数据源>
[WHERE <检索条件表达式>]
[GROUP BY <分组依据列>]
[HAVING <分组提取条件>]
[ORDER BY <排序依据列>]
1、查询指定列
在SELECT子句的<目标列名序列>中指定要查询的属性
SELECT Sno,Sname FROM Student
2.查询全部列
SELECT Sno,Sname,Ssex, Sage, Sdept FROM Student
等价于: SELECT * FROM Student
查询所有年龄在20岁以下的学生姓名及其年龄
SELECT Sname, Sage FROM Student WHERE Sage < 20
或:SELECT Sname, Sage FROM Student WHERE NOT Sage >= 20
常用查询条件
确定范围 ( BETWEEN…AND)
BETWEEN … AND … 包括临界值
NOT BETWEEN… AND … 不包括临界值
作用:查找属性值在或不在指定范围内的元组
说明: BETWEEN后是范围的下限(低值) AND后是范围的上限(高值)
字符匹配 (LIKE)
一般形式为: 列名 [NOT ] LIKE 匹配串
作用:查找指定列名与匹配串常量匹配的元组。
匹配串类型:匹配串可以是字符串常量,也可以含有通配符。
通配符种类:
%(百分号):匹配0个或多个字符。
_(下划线):匹配一个字符。
[ ]:匹配括号中的字符
[∧ ]:不匹配括号中的字符
查询所有不姓“刘”的学生
SELECT Sname FROM Student WHERE Sname NOT LIKE ‘刘%’
涉及空值的查询
空值是未确定的值或其值尚不知道
例如,学生选课,在开学初学生只有选课记录,没有修课成绩,这时成绩一项的值就是空值。
不能用=或<>,只能用IS NULL或IS NOT NULL
注意
空值不是一个确定的值,所以不可以用等于或不等于来比较或衡量;
空值只能说是空值(IS NULL)或不是空值(IS NOT NULL)。
多重条件查询
用逻辑运算符AND和OR组成多条件查询。
查询计算机系年龄在20岁以下的学生姓名
SELECT Sname FROM Student WHERE Sdept=‘CS’ AND Sage<20
对查询结果进行排序的子句为:
ORDER BY <列名> [<列名> … ] [ASC | DESC ]
说明:按<列名>进行升序(ASC)或降序(DESC)排序。
SQL提供的计算函数
COUNT(*):统计表中元组个数
COUNT(<列名>):统计本列非空列值个数
SUM(<列名>):计算列值总和(必须是数值型列)
AVG(<列名>):计算列值平均值(必须是数值型列)
MAX(<列名>):求列值最大值
MIN(<列名>):求列值最小值
对查询结果分组
作用:可以控制计算的级别(对全表还是对一组)
目的:细化计算函数的作用对象
分组语句的一般形式:
[WHERE <条件> ]
[GROUP BY <分组条件>] :对查询结果按分组条件的值分组
[HAVING <组自身条件>]:HAVING用于对分组自身进行限制,它有点象WHERE子句,但它用于组而不是对单个记录。
用INSERT语句记录
语法格式如下:
INSERT [ INTO]
table_name
{ [ ( column_list ) ]
{ VALUES
( { expression } [ ,…n] )
}
}
语法注释:
[INTO]:一个可选的关键字,可以将它用在 INSERT 和目标表之间。
table_name:将要接收数据的表或 table 变量的名称。
(column_list):要在其中插入数据的一列或多列的列表。必须用圆括号将column_list括起来,并且用逗号进行分隔。
VALUES:引入要插入的数据值的列表。对于column_list(如果已指定)中或者表中的每个列,都必须有一个数据值。 必须用圆括号将值列表括起来 。如果 VALUES 列表中的值与表中列的顺序不相同,或者未包含表中所有列的值,那么必须使用column_list明确地指定存储每个传入值的列。
修改数据
Update <表名> Set <列名>=<表达式>[{, <列名>=<表达式>}] Set 列名 表达式 [{, 列名 表达式 }] [Where <条件>]
将学生95001的年龄改为22岁 Update Student Set Sage = 22 Where Sno=95001
将所有学生的年龄增加1岁 Update Student Set Sage=Sage+1
Delete语句
删除数据 Delete From <表名>[Where <条件>]
删除学号为95019的学生的记录 Delete From Student Where Sno=95019
删除所有学生的选课记录 Delete From SC
六、C API
打开/不存在就创建
(C调用include sqlite3.h)
函数原型: int sqlite3_open(const char* fileName, sqlite3** ppDB);
函数功能:打开一个数据库;若该数据库文件不存在,则自动创建。打开或者创建数据库的命令会被缓存,直到这个数据库真正被调用的时候才会被执行。
输入参数:fileName,待打开的数据库文件名称,包括路径,以’\0’结尾; 特别说明:SQLite 支持内存数据库,内存方式存储使用文件名“:memory:”
输出参数:ppDB,返回打开的数据库句柄;
返回值:执行成功返回SQLITE_OK,否则返回其他值;
关闭
函数原型: int sqlite3_close(sqlite3* pDB);
函数功能:关闭一个打开的数据库;
输入参数:pDB,打开的数据库句柄
输出参数: 无
返回值:执行成功返回SQLITE_OK,否则返回其他值
调试
第一种:
函数原型: const char sqlite3_errmsg(sqlite3 pDB);
函数功能:获取最近调用的API 接口返回的错误说明,这些错误信息UTF-8的编码返回,并且在下一次调用任何SQLite API 函数时被自动清除;
输入参数:pDB,打开的数据库句柄
输出参数: 无
返回值:错误说明的字符串指针
第二种:
函数原型: int sqlite3_errcode(sqlite3* pDB);
函数功能:获取最近调用的API 接口返回的错误代码;
输入参数:pDB,打开的数据库句柄
输出参数: 无
返回值:错误代码
执行sql
函数原型: int sqlite3_exec(sqlite3* pDB, const char sql, sqlite_callback callback, voidpara, char** errMsg);
函数功能:编译和执行零个或多个SQL 语句,查询的结果返回给回调函数callback
输入参数:pDB,数据库句柄;sql,待执行的SQL 语句字符串,以’\0’结尾;callback,回调函数,用来处理查询结果,如果不需要回调(比如做insert 或者delete 操作时),可以输入NULL;para,用户传入的参数,可以为NULL,该参数指针最终会被传给回调函数callback,供用户在回调函数中使用;
输出参数:errMsg,返回错误信息,注意是指针的指针。
返回值:执行成功返回SQLITE_OK,否则返回其他值
回调函数
回调函数sqlite_callback介绍
typedef int (sqlite_callback)(void para,int columnCount,char** columnValue,char** columnName);
函数功能:由用户处理查询的结果
输入参数:para,从sqlite3_exec()传入的参数指针;columnCount, 查询到的这一条记录有多少个字段(即这条记录有多少列);columnValue,查询出来的数据都保存在这里,它实际上是个1 维数组(不要以为是2 维数组),每一个元素都是一个char * 值,是一个字段内容(用字符串来表示,以‘\0’结尾);columnName,与columnValue 是对应的,表示这个字段的字段名称。
输出参数:无
返回值:执行成功返回SQLITE_OK,否则返回其他值
☆回调函数最后要加上 return 0 或者SQLITE_OK
执行sql
函数原型: int sqlite3_get_table(sqlite3* pDB, const char *sql,char *pResult, int * rowCount,int * columnCount, char errMsg);
函数功能:执行SQL 语句,通过一维数组返回结果;一般用于数据记录查询
输入参数:pDB,打开的数据库句柄;sql,待执行的SQL 字符串,以’\0’结尾;
输出参数:rowCount,查询出多少条记录(即查出多少行);columnCount,查询出来的记录有多少个字段(多少列); errMsg,返回错误信息;pResult,查询结果,是由字符串组成的一维数组(不要以为是二维数组,更不要以为是三维数组)。它的内存布局是:第一行是字段名称,后面紧接着每个字段的值;
返回值:执行成功返回SQLITE_OK,否则返回其他值
释放
函数原型: void sqlite3_free_table(char **result);
函数功能:释放查询结果占用的内存;
输入参数:result,通过函数sqlite3_get_table()查询到的记录结果
输出参数:无
返回值:无
执行sql
函数原型: int sqlite3_prepare(sqlite3* pDB, const char* sql , int maxSqlLen,sqlite3_stmt** ppStmt, const char**pTail);
函数功能:将SQL 语句编译成SQLite 能够识别的二进制字节码(也即SQL声明,statement),结果保存在ppStat 中。注:输入的参数中只有第一个SQL语句会被编译。SQL 语句间通过分号‘;’分隔。
输入参数:pDB ,数据库句柄;sql ,待编译的SQL 语句字符串; maxSqlLen,SQL 语句的最大长度,如果此值小于0,SQLite 会自动计算字符串长度;
输出参数:ppStmt,编译后SQL 语句存放位置;pTail,未编译的SQL 语句的起始位置,一般输入NULL 就可以了。
返回值:执行成功返回SQLITE_OK,否则返回其他值