文章目录
关于数据库
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功能中的冰山一角,还有很多很多的数据库操作没有去实现,让我一时间实现一遍也不可能,只能在以后的项目实践中慢慢探索,仔细深挖。