使用香橙派学习 嵌入式数据库---SQLite

news2024/12/24 22:12:38

嵌入式数据库简介:SQLite & MySQL数据库

基于嵌入式的数据库主要有:SQLite,Firebird,Berkeley DB,eXtremeDB等

  • Firebird 是关系型数据库,功能强大,支持存储过程,SQL兼容等
  • SQLite 关系型数据库,体积小,支持ACID事务
  • Berkeley DB 并没有数据库服务器的概念,他的程序直接链接到应用程序中
  • eXtremeDB 是内存数据库,运行效率高

SQLite数据库

轻量化,易用的嵌入式数据库,用于设备端的数据管理,可以理解成单点的数据库。(传统服务器型数据库用于管理多端设备,更加复杂SQLite是一个无服务器的数据库,是自包含的。这也称为嵌入式数据库,这意味着数据库引擎作 为应用程序的一部分运行。

MySQL数据库

MySQL需要运行服务器,MySQL将需要客户端和服务器架构通过网络进行交互

在香橙派上安装SQLite3数据库

执行以下命令:

sudo apt-get -y install sqlite

安装成功后,执行“sqlite” 即可进入数据库命令行:

但是此时的版本是2.8.17,一般sqlite3的使用场景更多,所以我想升级以下版本,运行“sudo apt-get -y install sqlite3

但是报错,于是只能到官网去下载:SQLite Download Page 

进入官网后,选择Source Code下的第二个:

将下载的文件上传到香橙派:

 

然后,依次执行以下的命令:

tar xvf sqlite-autoconf-3430100.tar.gz //解压
cd sqlite-autoconf-3430100 //进入文件夹
./configure --prefix=/usr/local //配置安装路径在/usr/local
make //编译,这一步比较久,大概10分钟
sudo make install //安装

成功安装后,输入“sqlite3”:

可见,此时版本成功变成了3.43.1,并成功连入了数据库!

可以输入“ .quit ”退出:

SQLite的基本操作

在工作目录“/home/orangepi/”下创建“mjm_sqlite”文件夹,将数据库文件存放在这里:

数据库的创建/打开

方法1:
  1. 输入“sqlite3” 进入数据库
  2. 输入“.open test.db
  3. 输入“.quit” 退出

方法2:
  1. 输入“sqlite3 test.db” 在命令运行当前窗口创建数据库test.db
  2. 输入“.databases” 列出当前打开的数据库
  3. 输入“.quit” 退出

表格的创建/打开

数据库表格的创建和结构体很类似,在实际中也经常将两者进行转换:

create table stu(id Integer,name char,score Integer); //在这里“int”应该写成“Integer”,且写在变量名的后方

 

上图演示了:打开刚刚创建的test.db数据库,并在其中添加一张名为stu的表格,表格有三个字段:整型的id和score,char型的name

和“.databases”类似,输入“.tables”可以查看当前打开的表格:

数据库创建和表格创建的区别 

  • 执行“.open A.db”时,如果一个数据库A.db不存在则会创建并打开;若该数据库已经存在就会打开;且 “.open A.db”不是SQL命令,对应的C接口是sqlite3_open( )函数
  • 执行“create table AA(....)”时,如果表AA不存在则会创建并打开;若表格已经存在则会报错;且 “create table AA(....)”是SQL命令,对应的C接口是sqlite3_exec( )函数

插入一条记录

insert into stu values(18130106,'huang',99); //这个版本的sqlite只能使用'huang'而不能使用"huang"!!!

//也可以此一次只插入部分的字段内容,比如只插入name和score,不插入id
insert into stu(name,score) values('huanggang',77); //插入部分字段内容

 

上图分别演示了:将一个名为huang的同学的id,name,score 插入stu表格;将一个名为huanggang的同学的name,score部分插入stu表格

查看数据库的记录

select * from stu; //查询所有字段的结果
select name,score from stu; //查询数据库中部分字段的内容

 

上图分别演示了:查看stu表格的所有记录;查看stu表格下name和score的全部记录

删除一条记录

delete from stu where id = 18130106;

 

上图演示了:删除了id为18130106的记录,即名为“huang”的同学的记录被删除了,所以只剩下了“huanggang”同学

更改一条记录

update stu set name = 'majia' where score = 77;

上图演示了:将分数为77的同学的名字修改为“majia”

增加一列

alter table stu add column sex char;

 

上图演示了:为stu表格新增一列char型的sex的字段,然后将分数为77的同学的id设为12133,sex设为male

删除一张表

drop table stu;

 

上图演示了:删除stu表格

错误处理方式

当输入了无法识别的指令,数据库会进入“...>”的状态:

此时输入“CTRL + Z” 就可以强制退出:

SQLite的编程操作

在学习了SQlite的基本操作之后,虽然有能力进行数据基本的增删改查,但是都需要输入“sqlite3”在数据库命令行来执行,我希望实现的是更自动化的运行,比如我的程序在获取数据后可以自动写入数据库,这就需要学习如何打开/创建数据库的C接口

打开/创建数据库的C接口

sqlite3_open(const char *filename, sqlite3 **ppDb)
  • 该指令打开一个指向 SQLite 数据库文件的连接,返回一个用于其他 SQLite 程序的数据库连接对象。 
sqlite3_close(sqlite3*)
  • 该指令关闭之前调用 sqlite3_open() 打开的数据库连接。
  • 所有与连接相关的语句都应在连接关闭之前完成。 如果还有查询没有完成,sqlite3_close() 将返回 SQLITE_BUSY 禁止关闭的错误消息。
const char *sqlite3_errmsg(sqlite3*);
  • 该指令通常用来获取最近调用的API接口返回的错误代码
  • 错误代码一览:

例程sql_demo1.c:
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    sqlite3 *db;
    char *zErrMsg = 0;
    int ret;

    if(argc < 2){
        printf("Usage: %s xxx.db\n",argv[0]);
        return -1;
    }

    ret = sqlite3_open(argv[1], &db);

    if(ret != SQLITE_OK){
        printf("Can't open database: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Opened database successfully\n");
    }
    sqlite3_close(db);
    printf("close database\n");
}
实现效果: 

使用gcc编译会报错,需要链库,所以可以和之前一样写一个shell脚本

buildsql.sh:

gcc $1 -lsqlite3

然后输入“chmod +x buildsql.sh”赋予权限就可以了 

如果test.db本来就存在,那么“./a.out test.db” 也会成功运行,只不过从“创建test.db并关闭”变成了“打开test.db并关闭”

sqlite3_exec函数的引入 & SELECT操作

在学习接下来的操作之前,需要学习这个sqlite3_exec( )和其对应的callback( )函数:

sqlite3_exec(sqlite3*, const char *sql, sqlite_callback, void *data, char **errmsg)
  • 该指令提供了一个执行 SQL 命令的快捷方式,SQL 命令由 sql 参数提供,可以由多个 SQL 命令组成,此处命令的不同就决定了实现功能的不同,所以之后创建表;插入数据;SELECT;UPDATE;DELETE本质上都是调用这个函数,只不过这个参数的值和callback的处理可能不同
  • 第一个参数 sqlite3 是打开的数据库对象
  • sqlite_callback 是一个回调,data 作为回调函数的第一个参数
  • errmsg 将被返回用来获取程序生成的任何错误
int callback(void *arg, int column_size, char *column_value[], char *column_name[])
  • 第一个参数void *arg 是sqlite3_exec函数的第四个参数data
  • column_size:数据库的字段 数
  • column_value[ ]:列的值
  • column_name:字段名字 

为了验证这个函数,可以先写一个demo执行一句简单的sql指令:

例程sql_demo2.c: (实现“select * from stu;”的sql指令
#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>


int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);

	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}


int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;

	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}

	/*open database*/
	ret = sqlite3_open(argv[1], &db);

	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}

	/* execute sql statement */
	ret = sqlite3_exec(db, "select * from stu;", callback, 0, &zErrMsg);

	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}

为什么 &zErrMsg不会报段错误?因为如果发生错误,函数底层应该会为zErrMsg分配空间然后写入错误信息。

实现效果:

 

创建表 & 插入数据

小插曲1:

“ .tables ” 不属于SQL语句,所以这句命令写在sqlite3_exec( )中会出错!

判断表格是否存在只需要在sqlite3_exec( )中写创建表格的SQL语句,然后通过返回值来判断表格是否存在即可!

小插曲2:

sqlite3_exec( )函数中的提到的callback函数是不一定会执行的,比如SQL指令是创建表格或插入数据,那么callback就不会执行(对应在sql环境下输入创建表格或插入数据的指令也不会输出任何东西),但如果执行SELECT指令的话callback函数就会执行(对应在sql环境下输入SELECT语句会显示对应的结果),所以可以粗略概括为:只有在SQL环境下会有反馈输出的SQL指令出现在sqlite3_exec( )函数中,callback才会被调用

小插曲3:

  • PRIMARY KEY是主键值的意思,主键值必须是能够区分每一行数据的值,比如ID是主键值,那每一组数据的ID都应该是不同的。
  • 而如果一个字段被指定了“NOT NULL”,就代表这个字段不能为空

小插曲4:

再次提醒,在SQL命令中,字符串要使用'XXX'而不是"XXX"!! 

例程sql_demo3.c:

创建一个名为“company”的表格

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>


int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);

	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}


int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;
	char *sql;

	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}

	/*open database*/
	ret = sqlite3_open(argv[1], &db);

	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}

	/* execute sql statement -- create table */ 
	sql = "CREATE TABLE COMPANY(" \
           "ID INT PRIMARY KEY NOT NULL," \
           "NAME CHAR(30) NOT NULL," \
           "AGE INT NOT NULL," \
           "ADDRESS CHAR(50)," \
           "SALARY REAL );";

	ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't create table: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Table create successfully\n");
	}

	/* execute sql statement -- insert data */
	sql = "insert into company values(1813,'company.1',3,'aaa street No.293',37732);";

    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't insert data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Inset data successfully\n");
    }

	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content: %s\n", sqlite3_errmsg(db));
        exit(0);
    }


	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}
实现效果: 

我重新创建了一个叫“companydb.db”的数据库来存放这个表格

可见,表格和数据分别创建和插入成功 ,并且callback只有最后一次SELECT命令时才被调用

再尝试进入SQL环境验证:

 

并且,如果再次执行命令就会报错,并提示表格已经存在

UPDATE操作 & DELETE操作

例程sql_demo4.c:

对于刚刚创建的company表格,更新它的地址,然后删除这条记录

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>


int callback(void *arg, int column_size, char *column_value[], char *column_name[])
{
	int i;
	printf("arg=%s\n",(char *)arg);

	for(i=0;i<column_size;i++){
		printf("%s = %s\n", column_name[i], column_value[i]);
	}
	printf("=======================\n");
	return 0;//必须返回0,这样数据库中有多少条数据,这个回调函数就会被调用多少次
}


int main(int argc, char** argv)
{
	sqlite3 *db;
	char *zErrMsg = 0;
	int ret;
	char *sql;

	if(argc < 2){
		printf("Usage: %s xxx.db\n",argv[0]);
		return -1;
	}

	/*open database*/
	ret = sqlite3_open(argv[1], &db);

	if(ret != SQLITE_OK){ 
		printf("Can't open database: %s\n", sqlite3_errmsg(db));
		exit(0);
	}else{
		printf("Opened database successfully\n");
	}

	/* execute sql statement -- create table */ 
	sql = "CREATE TABLE COMPANY(" \
           "ID INT PRIMARY KEY NOT NULL," \
           "NAME CHAR(30) NOT NULL," \
           "AGE INT NOT NULL," \
           "ADDRESS CHAR(50)," \
           "SALARY REAL );";

	ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
	if(ret != SQLITE_OK){
		printf("Can't create table: %s\n", sqlite3_errmsg(db));
		//exit(0); 这里将exit注释掉的原因是如果表格已经存在,不需要退出,而是继续执行即可
	}else{
		printf("Table create successfully\n");
	}

	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "before update", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content1: %s\n", sqlite3_errmsg(db));
        exit(0);
    }

	/* execute sql statement -- update data */
    sql = "update company set address = 'ccc street No.666' where id = 1813;";

    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't update data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Update data successfully\n");
    }

	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "after update", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content2: %s\n", sqlite3_errmsg(db));
        exit(0);
    }

	/* execute sql statement -- delete data */
    sql = "delete from company where id = 1813;";

    ret = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't delete data: %s\n", sqlite3_errmsg(db));
        exit(0);
    }else{
        printf("Delete data successfully\n");
    }

	/* execute sql statement -- show content */
    ret = sqlite3_exec(db, "select * from company;", callback, "after delete", &zErrMsg);
    if(ret != SQLITE_OK){
        printf("Can't show content3: %s\n", sqlite3_errmsg(db));
        exit(0);
    }


	/* close database */
	sqlite3_close(db);
	printf("close database\n");
	return 0;
}
实现效果: 

可见,由于表格已经存在,所以创建表格的命令出错了,不过由于我的修改,代码会继续运行而不是直接exit更新数据后,地址的确改变了而删除数据后,由于本来就只有一条记录,所以此时company表没有数据,所以此时哪怕调用了“select * from company;” sqlite3_exec函数也不会调用callback来打印信息!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1036312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

XCTF之新手Web题目

新手第一题&#xff1a;Training-WWW-Robots 图片提示&#xff1a; 解题流程&#xff1a; 具体操作&#xff1a;打开菜单-->Web开发者-->查看器&#xff08;或者快捷键ctrlshiftc&#xff09; robots.txt文件被网络爬虫使用&#xff0c;以检查它们是否被允许抓取和索引…

普通人也能秒变电子画册制作达人

你是不是觉得制作电子画册很难&#xff1f;需要专业的设计知识和软件&#xff1f;今天&#xff0c;小编告诉你&#xff0c;制作电子画册并不难&#xff01;只要掌握一些简单技巧&#xff0c;你也可以轻松制精美的电子画册。下面&#xff0c;让我们一起来看看&#xff0c;如何从…

以太网协议

以太网 以太网协议格式&#x1f3a8;目的地址,源地址mac地址格式 以太网协议格式&#x1f3a8; 目的地址,源地址 此处的地址,叫做mac地址(物理地址),长度是6个字节 mac地址的作用也是用来区分不同的主机 IP地址的长度是4字节 IP地址负责网络层(整体)转发,mac地址负责数据链路层…

【斗罗2】霍雨浩实力被否定,超级斗罗眼光被嘲,魂导院成功捡漏

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析斗罗大陆2绝世唐门。 最新一集《绝世唐门》已经更新&#xff0c;相信不少小伙伴和小郑一样都已经先睹为快&#xff0c;本集虽然是过渡剧情&#xff0c;但本身还是有不少有意思的剧情&#xff0c;作为过渡文戏也算是可圈可…

服务器挂机策略

title: “服务器挂机” createTime: 2022-05-11T11:05:4308:00 updateTime: 2022-05-11T11:05:4308:00 draft: false author: “name” tags: [“服务器”] categories: [“服务器”] description: “测试的” 服务器挂机策略 地址&#xff1a;pve.dongshanxia.top:35000用户…

Leetcode 451. 根据字符出现频率排序

文章目录 题目代码&#xff08;9.24 首刷自解&#xff09; 题目 Leetcode 451. 根据字符出现频率排序 代码&#xff08;9.24 首刷自解&#xff09; class Solution { public:string frequencySort(string s) {unordered_map<char, int> mp;for(char&c : s)mp[c];au…

SQL 基础知识梳理(一)- 数据库与 SQL

目录 一、Whats 数据库二、数据库结构三、SQL 概要四、创建数据库与表五、更新和删除表 一、What’s 数据库 1.数据库&#xff08;Database&#xff0c;DB&#xff09;&#xff1a;将大量数据保存起来&#xff0c;通过计算机加工而成的可以进行高效访问的数据集合。如&#xf…

三、支持向量机算法(SVC,Support Vector Classification)(有监督学习)

支持向量机Support Vector Machine&#xff0c;就是所谓的SVM&#xff0c;它指的是一系列的机器学习算法&#xff0c;根据解决问题的不同&#xff0c;分为SVC(分类)和SVR(回归) SVC&#xff0c;Support Vector Classification&#xff0c;其本质也是支持向量机support vector&…

Visopsys 小型操作系统

Visopsys 是一个 PC 机的操作系统&#xff0c;系统小型、快速而且开源。有着丰富的图形界面、抢先式多任务机制以及支持虚拟内存。Visopsys 视图兼容很多操作系统&#xff0c;但并不是他们的克隆版本。Visopsys 0.92 现已发布&#xff0c;此维护版本引入了多任务处理程序、文件…

js逆向-某税务网站chinatax分析

目录 一、如图网站二、研究登陆页反爬参数1、datagram参数2、请求接口关系 三、研究详情页反爬参数1、urlyzm与ruuid与x-b3-spanid参数2、los28199参数3、lzkqow23819参数4、jmbw参数 四、最终结果 一、如图网站 二、研究登陆页反爬参数 1、datagram参数 很多接口使用到的dat…

PyCharm 手动下载插件

插件模块一直加载失败&#xff0c;报错信息&#xff1a; Marketplace plugins are not loaded. Check the internet connection and refresh. 尝试了以下方法&#xff0c;均告失败&#xff1a; pip 换源Manage Plugin Repositories...HTTP 代理设置...关闭三个防火墙 最后选…

Spring面试题5:面试官:为什么说Spring是一个容器?如何给Spring容器提供配置元数据?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:为什么说Spring是一个容器? Spring被称为一个容器,是因为它提供了一个运行环境和管理机制,用于管理应用程序中的对象的生命周期和依赖关系。 …

C#中对泛型集合元素使用List.Sort()方法排序

啊&#xff01;终于整明白了&#xff01; 今天拿出一点时间研究了一下C#的List<T>如何排序&#xff0c;基本上整明白了。很多场景下&#xff0c;用这个排序还是很方便的。 //构造一个类 public class mth{//编号private string id;public string Id{get { return id; …

Python四大数据结构整理

Python四大数据结构整理 列表列表本身的基础造作操作列表的增删改查列表总结 字典字典的创建获取字典视图遍历字典字典生成式 元组与集合元组的创建元组的获取集合集合的创建方式集合的相关操作 对比归纳总结 列表 列表的特点   1.列表元素按顺序有序排放   2.索引映射唯一…

Linux---su:鉴定故障

问题来源:在使用xshell操作Linux命令时,切换root权限报错 可能是未设置密码:输入 sudo password 重新设置一下密码即可 本人犯的错: 因为在Linux下输入密码是没有显示的,然后我的键盘num键没开!!!(也就是输入数字开关的键盘),导致我认为我的密码输进去了,给我整懵逼了&#x…

十四、流式编程(4)

本章概要 终端操作 数组循环集合组合匹配查找信息数字流信息 终端操作 以下操作将会获取流的最终结果。至此我们无法再继续往后传递流。可以说&#xff0c;终端操作&#xff08;Terminal Operations&#xff09;总是我们在流管道中所做的最后一件事。 数组 toArray()&…

Docker Dockerfile解析

Dockerfile是什么 Dockerfile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像所需的指令和参数构成的脚本。 官网&#xff1a;Dockerfile reference | Docker Docs 构建三步骤&#xff1a; 编写Dockerfile文件docker build命令构建镜像docker run依镜像运行容…

Bun 1.0 正式发布,爆火的前端运行时,速度遥遥领先!

文章目录 一、包子1.0二、Bun 是一个一体化工具包为什么包子存在 二、Bun 是一个 JavaScript 运行时Node.js 兼容性速度TypeScript 和 JSX 支持ESM 和 CommonJS 兼容性网络 API热重载插件 一、包子1.0 Bun 1.0终于来了。 Bun 是一个快速、一体化的工具包&#xff0c;用于运行…

云原生微服务治理:服务发现、负载均衡与熔断策略

文章目录 什么是云原生微服务治理&#xff1f;服务发现客户端发现服务器端发现 负载均衡Ribbon - 基于客户端的负载均衡Nginx - 基于服务器的负载均衡 熔断策略Hystrix - 熔断器模式 结论 &#x1f389;欢迎来到云计算技术应用专栏~云原生微服务治理&#xff1a;服务发现、负载…

【AI视野·今日Robot 机器人论文速览 第三十九期】Fri, 22 Sep 2023

AI视野今日CS.Robotics 机器人学论文速览 Fri, 22 Sep 2023 Totally 39 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers ForceSight: Text-Guided Mobile Manipulation with Visual-Force Goals Authors Jeremy A. Collins, Cody Houff, You Liang …