嵌入式数据库--sqlite

关于数据库

1、客户端、服务器和数据库

  • 服务器:保存、处理、分发数据。
  • 客户端:收集、展示数据。
  • 数据库:规范地管理和存储数据。
  • 三者之间的关系:

在这里插入图片描述

2、目前国内比较流行的数据库管理系统

  • Mysql
    Mysql是开源的、快速的、可靠的、易于使用的关系型数据库管理系统,Mysql可以工作在嵌入式系统中,功能比较强大,内存占用比较大。

  • sql server
    微软开发的用于web服务器上最流行的数据库管理系统,以其简便的操作和友好的界面深受广大用户的喜爱。

  • oracle
    甲骨文公司研发的开放的数据库管理系统,操作较为复杂,功能比较强大,在世界上应用最广泛的数据库。

  • 总结
    在当今大数据形势的推动下,数据的管理极为重要,事物的诞生往往是因为需求,数据库就是用来管理和保护数据的。数据库技术的发展越来越完善,各个数据库之间没有谁强谁弱之说,只能说各个数据库的使用场合不一样,比如在嵌入式领域,数据库往往是用来暂时存储小量数据的,基本轻量级的数据库就可以满足需求,大型复杂的数据库管理系统反而会影响嵌入式系统的运行效率。

sqlite介绍

  • sqlite的背景
    sqlite是全开源的,可以免费用作任何目的。SQLite代码库由一支全职从事SQLite工作的国际开发人员团队支持 。开发人员继续扩展SQLite的功能并增强其可靠性和性能,同时保持与已发布的接口规范, SQL语法和数据库文件格式的向后兼容性 。源代码对于任何想要它的人都是绝对免费的,但是也可以提供专业支持。

  • 为什么适用于嵌入式
    sqlite是c语言编写的嵌入式数据库管理系统,代码量少于3万行,库小于600KB,称其为轻量级数据库,它仅仅是一个“库”,并不是数据库服务器,因此不需要单独的服务器进程,sqlite直接读取和写入磁盘文件,根据系统提供的内存大小,运行速度不一样,一般情况下,内存越大,运行速度越快,可能比直接文件系统IO–fwrite、fread快(参考链接)。

  • 特点
    (1)无服务器:大多少数据库基于客户端/服务器的,通过网络访问数据库服务器。sqlite直接存取磁盘,没有中间服务器层,主要优点是无需安装,设置,配置,初始化,管理和排除故障的单独服务器进程,正所谓"零配置"数据库引擎。

    (2)单个数据库文件:sqlite数据库是单个普通磁盘文件,可以位于目录层次结构中的任何位置。其他数据库引擎倾向于将数据存储为大量文件,并只能存放在数据库本身标准的位置,这样做是为了保证数据的安全性,同时也给访问带来了困难。

    (3)稳定的可跨平台数据库文件:可以在不同平台间复制并使用相同的数据库文件。

    (4)清单输入:sqlite允许用户将任意类型的值存放在任意列中,这种数据类型叫清单类型,sqlite所特有。

    (5)可变长度记录:sqlite仅使用一行记录所占用的磁盘空间,比如将单个字符存放在VARCHAR(100)列中,磁盘空间仅仅被消耗一个字符的空间,而不是100个字符的空间。这是sqlite数据库比较小的原因之一,数据库越小,运行越快。

sqlite的shell命令

  • ubuntu上安装sqlite3:只需要一条命令即可:sudo apt-get install sqlite3; 中间可能会出现缺少依赖包这种情况,我们只需下载相应的依赖包就好了。

  • 启动sqlite3控制台:sqlite3
    在这里插入图片描述

  • 创建一个test的表:create table test (varchar,int);
    在这里插入图片描述

  • 查看数据库中所有的表:.table;
    在这里插入图片描述

  • 向表中插入两条数据:insert into test values();
    在这里插入图片描述

  • 查看表中所有数据:select * from test;
    在这里插入图片描述

  • 删除表:drop table test;
    在这里插入图片描述

  • 更多的SQL语句:点击学习

sqlite C API接口

Linux下使用编程操作sqlite数据库时,会在c文件中包含<sqlite3.h>头文件,如果编译出现下图所示错误,说明没有相应的函数库。在这里插入图片描述
解决办法:

sudo apt-get install libsqlite3-dev

1、连接数据库

连接sqlite3数据库,如果数据库不存在,则创建并打开数据库,如果此数据库存在,则打开数据库。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sqlite3.h>

#define database_name "test.db"//数据库的名字

int main(int argc, char **argv)
{

	sqlite3				*db;//定义数据库操作句柄

	int					rv = -1;//函数返回值

	rv = sqlite3_open(database_name,&db);//打开数据库
	printf("rv=%d\n",rv);//打印返回值
	if(rv < 0)
	{
		printf("Can't create or open database!:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	else
	{
		printf("Creating or opening database successfully!\n");
	}

	rv = sqlite3_close(db);//关闭数据库
	printf("rv=%d\n",rv);//打印返回值
	if(rv < 0)
	{
		 printf("Closing database failly!:%s\n",sqlite3_errmsg(db));
		 exit(0);
	}
	else
	{
		printf("select table successfully!\n");
	}
}

代码解析:

  • sqlite3_open
int sqlite3_open(
 			 	const char *filename,   /*数据库的名字*/
				sqlite3 **ppDb          /*输出数据库的操作句柄*/
 				);

功能:按文件名称打开一个数据库,如果文件不存在,则自动创建。
返回:创建或打开成功返回SQLITE_OK(0),错误返回错误码。
返回值列表:

#define SQLITE_OK 0 /* Successful result /
/
beginning-of-error-codes /
#define SQLITE_ERROR 1 /
SQL error or missing database /
#define SQLITE_INTERNAL 2 /
Internal logic error in SQLite /
#define SQLITE_PERM 3 /
Access permission denied /
#define SQLITE_ABORT 4 /
Callback routine requested an abort /
#define SQLITE_BUSY 5 /
The database file is locked /
#define SQLITE_LOCKED 6 /
A table in the database is locked /
#define SQLITE_NOMEM 7 /
A malloc() failed /
#define SQLITE_READONLY 8 /
Attempt to write a readonly database /
#define SQLITE_INTERRUPT 9 /
Operation terminated by sqlite3_interrupt()/
#define SQLITE_IOERR 10 /
Some kind of disk I/O error occurred /
#define SQLITE_CORRUPT 11 /
The database disk image is malformed /
#define SQLITE_NOTFOUND 12 /
Unknown opcode in sqlite3_file_control() /
#define SQLITE_FULL 13 /
Insertion failed because database is full /
#define SQLITE_CANTOPEN 14 /
Unable to open the database file /
#define SQLITE_PROTOCOL 15 /
Database lock protocol error /
#define SQLITE_EMPTY 16 /
Database is empty /
#define SQLITE_SCHEMA 17 /
The database schema changed /
#define SQLITE_TOOBIG 18 /
String or BLOB exceeds size limit /
#define SQLITE_CONSTRAINT 19 /
Abort due to constraint violation /
#define SQLITE_MISMATCH 20 /
Data type mismatch /
#define SQLITE_MISUSE 21 /
Library used incorrectly /
#define SQLITE_NOLFS 22 /
Uses OS features not supported on host /
#define SQLITE_AUTH 23 /
Authorization denied /
#define SQLITE_FORMAT 24 /
Auxiliary database format error /
#define SQLITE_RANGE 25 /
2nd parameter to sqlite3_bind out of range /
#define SQLITE_NOTADB 26 /
File opened that is not a database file /
#define SQLITE_ROW 100 /
sqlite3_step() has another row ready /
#define SQLITE_DONE 101 /
sqlite3_step() has finished executing /
/
end-of-error-codes */

  • sqlite3_errmsg
int sqlite3_errmsg(sqlite3 *);

功能:打印数据库错误信息。
参数:数据库操作句柄
返回:创建或打开成功返回SQLITE_OK(0),错误返回错误码。

  • sqlite3_close
int sqlite3_close(sqlite3 *;

功能:关闭数据库。
参数:数据库操作句柄
返回:创建或打开成功返回SQLITE_OK(0),错误返回错误码。

  • 编译运行
    1、出现以下错误,原因是sqlite3不是标准库,gcc编译连接不上sqlite3函数库
    在这里插入图片描述
    解决办法:加上 -lsqlite3
    在这里插入图片描述
    2、运行,成功打开数据库
    在这里插入图片描述
    3、查看刚刚创建的数据库文件
    在这里插入图片描述

2、创建表

在前面创建test.db数据库中创建一个表。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>

/*
 功能:回调函数
 参数:
	para:由exec传入的参数
	col_num:查询出一条记录有多少个表头
	col_value:查询出的记录缓存区
	col_name:表示字段的段命
  返回:
	成功返回0
	失败返回-1
 */
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
	int i;
	for(i = 0; i < col_num; i++)
	{
		printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
	}
	printf("\n");

	return 0;
}


int main(int argc, char **argv)
{
	sqlite3					*db;//定义数据库操作句柄
	int						rv;//返回值
	char					*sql;//SQL语句指针
	char					*z_err_msg;//获取错误信息

	rv = sqlite3_open("test.db",&db);//打开数据库
	if(rv)
	{
		printf("Can't open database!:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	printf("Opening database successfully!\n");

	//制作SQL语句
	sql = "create table roommates("\
		   "stu_id varchar primary key not NULL,"\
		   "name		   text not NULL,"\
		   "age			   int  not NULL,"\
		   "address        varchar,"\
		   "telephone      varchar);";

	rv = sqlite3_exec(db,sql,callback,0,&z_err_msg);//执行sql语句
	if(rv)
	{
		printf("SQL error!:%s\n",z_err_msg);//打印错误信息
		sqlite3_free(z_err_msg);
	}
	else
	{
		printf("select table successfully!\n");
	}

	sqlite3_close(db);//关闭数据库

	return 0;
}

代码解析:

  • sqlite3_exec
int  sqlite3_exec{
				sqlite3*            : open 打开的数据库操作句柄
				const char* sql,    : 执行的sql功能语句
				*callback,          : sql语句对应的回调函数,在下一个实例代码中细讲
				void* data,         : 传递给回调函数的参数
				char **errmsq       : 函数内部通过malloc返回错误信息
				}

功能:执行sql语句
返回:成功返回SQLITE_OK,错误返回错误代码

  • sqlite3_free
int sqlite3_free(char *errmsq);

功能:当执行exec函数时,如果发生错误,内部会malloc分配内存存储错误信息,所以需要释放这块内存,以免内存泄漏。
返回:成功返回SQLITE_OK,错误返回错误代码。

  • 编译运行
    在这里插入图片描述
  • 查看刚刚建的表字段
    在这里插入图片描述

3、插入数据

向上面创建的roommates表中插入数据。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>

/*
 功能:查询记录回调函数
 参数:
	para:由exec传入的参数
	col_num:查询出一条记录有多少个表头
	col_value:查询出的记录缓存区
	col_name:表示字段的段命
  返回:
	成功返回0
	失败返回-1
 */
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
	int i;
	for(i = 0; i < col_num; i++)
	{
		printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
	}
	printf("\n");

	return 0;
}

int main(int argc, char **argv)
{

	sqlite3					*db;//定义数据库操作句柄
	int						rv;//返回值
	char					*sql;//SQL语句指针
	char					*z_err_msg;//获取错误信息

	rv = sqlite3_open("test.db",&db);//打开数据库
	if(rv)
	{
		printf("Can't open database!:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	printf("Opening database successfully!\n");

	//制作SQL语句
	sql =  "insert into roommates(stu_id,name,age,address,telephone)"\
		   "values('12057','Mr Yang',21,'si chuan','96325874');"\
		   "insert into roommates(stu_id,name,age,address,telephone)"\
		   "values('12060','Mr qing',22,'yun nan','96325789');"\
		   "insert into roommates(stu_id,name,age,address,telephone)"\
		   "values('12059','Mr wang',20,'gui zhou','96325456');"\
		   "insert into roommates(stu_id,name,age,address,telephone)"\
		   "values('12065','Mr qi',22,'shang xi','96325874');";


	rv = sqlite3_exec(db,sql,callback,0,&z_err_msg);//执行sql语句
	if(rv)
	{
		printf("SQL error!:%s\n",z_err_msg);//打印错误信息
		sqlite3_free(z_err_msg);//用于释放从内存中获取的错误信息字符串
	}
	else
	{
		printf("select table successfully!\n");
	}
	sqlite3_close(db);//关闭数据库

	return 0;
}

  • 编译运行
    在这里插入图片描述
  • 查看表中数据
    在这里插入图片描述

4、查询数据

通过c语言编程接口查询出roommates表中得记录。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>



/*
 功能:查询记录回调函数
 参数:
	para:由exec传入的参数
	col_num:查询出一条记录有多少个表头
	col_value:查询出的记录缓存区
	col_name:表示字段的段命
  返回:
	成功返回0
	失败返回-1
 */
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
	int i;
	printf("%s\n",(char*)para);
	for(i = 0; i < col_num; i++)
	{
		printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
	}
	printf("\n");

	return 0;
}


int main(int argc, char **argv)
{

	sqlite3					*db;//定义数据库操作句柄
	int						rv;//返回值
	char					*sql;//SQL语句指针
	char					*z_err_msg;//获取错误信息
	char					*data = "callback is called:";

	rv = sqlite3_open("test.db",&db);//打开数据库
	if(rv)
	{
		printf("Can't open database!:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	printf("Opening database successfully!\n");

	//制作SQL语句
	sql =  "select * from roommates";


	rv = sqlite3_exec(db,sql,callback,(void *)data,&z_err_msg);//执行sql语句
	if(rv)
	{
		printf("SQL error!:%s\n",z_err_msg);//打印错误信息
		sqlite3_free(z_err_msg);//用于释放从内存中获取的错误信息字符串
	}
	else
	{
		printf("select table successfully!\n");
	}
	

	sqlite3_close(db);//关闭数据库

	return 0;
}

  • 编译运行
    在这里插入图片描述
    咦?我们会发现一个问题,前面连接数据库、创建表、插入数据例程中都有设置回调函数,但是都没有被调用,这里查询记录却调用了四次,这是什么原因呢?

    回调函数,专门用来处理查询记录的结果,比如在这里,roommates表中一共有四条记录,所以回调函数被调用了四次,每次调用输出一条记录,像连接数据库、创建表、插入数据例程中不需要回调函数可以直接传参NULL。回调函数原型如下:

    这里我想再进一步解释一下columnValue和columnName这两个二级指针,其余两个参数在上面程序中有说明。

printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");

col_name、col_value:表示一个二级指针,也就是存放指针的数组。col_name表示存放字段的地址,
col_value表示字段下面的值的地址。

col_name[i]、col_value[i]:表示一个一级指针,col_name[i]表示存放字段字符串的首地址,
col_value[i]表示存放字段下面值字符串的地址。因为字段和值都是字符串。
typedef int (*sqlite_callback)(void* para,int columnCount,char** columnValue,char** columnName);

5、删除表中所有记录

c语言实现删除上面例程插入roommates表中的数据。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sqlite3.h>

/*
 功能:查询记录回调函数
 参数:
	para:由exec传入的参数
	col_num:查询出一条记录有多少个表头
	col_value:查询出的记录缓存区
	col_name:表示字段的段命
  返回:
	成功返回0
	失败返回-1
 */
static int callback(void *para, int col_num, char **col_value, char **col_name)
{
	int i;
	printf("%s\n",(char*)para);
	for(i = 0; i < col_num; i++)
	{
		printf("%s = %s\n",col_name[i],col_value[i]?col_value[i]:"NULL");
	}
	printf("\n");

	return 0;
}

int main(int argc, char **argv)
{

	sqlite3					*db;//定义数据库操作句柄
	int						rv;//返回值
	char					*sql;//SQL语句指针
	char					*z_err_msg;//获取错误信息
	char					*data = "callback is called:";

	rv = sqlite3_open("test.db",&db);//打开数据库
	if(rv)
	{
		printf("Can't open database!:%s\n",sqlite3_errmsg(db));
		exit(0);
	}
	printf("Opening database successfully!\n");

	//制作SQL语句
	sql =  "delete from roommates";


	rv = sqlite3_exec(db,sql,callback,(void *)data,&z_err_msg);//执行sql语句
	if(rv)
	{
		printf("SQL error!:%s\n",z_err_msg);//打印错误信息
		sqlite3_free(z_err_msg);//用于释放从内存中获取的错误信息字符串
	}
	else
	{
		printf("delete recodes successfully!\n");
	}

	sqlite3_close(db);//关闭数据库

	return 0;
}

  • 编译运行
    在这里插入图片描述
  • 再次查看表中是否有数据存在
    在这里插入图片描述
    从图中可以看出roommates表中已经没有数据存在了。

总结一下

从以上的五个例程中可以看出,sqlite数据库最重要的三大API接口分别是sqlite3_open、sqlite3_exec、sqlite3_close。这三个函数就可以轻松操作sqlite数据库,只需要将SQL语句换成相应的操作语句就ok,简单易行,没有复杂可言,当然在这里我只是演示一下sqlite功能中的冰山一角,还有很多很多的数据库操作没有去实现,让我一时间实现一遍也不可能,只能在以后的项目实践中慢慢探索,仔细深挖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章