嵌入式数据库SQLite 3配置使用详细笔记教程

0、惨痛教训

        随着管理开发的项目体积越来越庞大,产品系统涉及的数据量也越来越多,并且伴随着项目不久就要交付给甲方了。如果项目的数据信息没有被妥善管理,后期设备的运行状态、操作状况等数据流信息不能被溯源,当出现了一些特殊意外时,就会导致对于故障信息不能迅速准确的追踪,甚至会被甩锅、推卸责任,白白当了冤大头。因此对于嵌入式项目中,其产品运行时的数据库建立非常有必要,且是迫在眉睫!!!

        目前常用的数据库系统有:MySQL、PostgreSQL、Oracle Database、Microsoft SQL Server、SQLite等。在嵌入式项目中,前面几个数据库显然是不合适的,而SQLite是一个轻量级的数据库管理系统,它包含在一个C库中,提供了零配置、无服务器、事务性的SQL数据库引擎。所以SQLite的特点使其非常适合嵌入式系统、移动设备、小型项目或者作为应用程序的本地数据库使用。本文选用了嵌入式数据库SQLite3进行配置和讲解。

1、Sqlite3环境配置

(1)、下载安装SQLite库

根据目标系统平台,下载sqlite源码,或下载官方提供的已经编译好的库。本文目标平台是Windows11 64位平台,进入SQLite Download Page的主页,选择需要的库版本(Windows)。

下载的压缩包一共有如下所示的三个:

sqlite-dll-win-x64-3450300.zip

sqlite-dll-win-x86-3450300.zip

sqlite-tools-win-x64-3450300.zip

(2)、解压下载的文件

        本文中将对应的Sqlite库文件解压到了,C:\Program Files\sqlite路径下。

(3)、添加库路径到环境变量

        根据下图所示的步骤,进入系统属性-->环境变量-->系统变量-->编辑环境变量,将路径加入到环境变量中。

(4)、检查数据库安装状态

        打开Windows的命令行,输入sqlite3,有类似如下的数据信息说明库安装成功,后续只需在程序代码中,将库加入到工程代码中即可。

(5)、SQLiteStudio工具

        如果有可视化分析数据需求、推荐使用下载:SQLiteStudioicon-default.png?t=N7T8https://sqlitestudio.pl/

2、SQLite3基础

        SQL(Structured Query Language)是一种结构化查询语言,SQL 是一种专门用来与数据库通信的语言。

        不同的数据库管理系统在其实践过程中都对 SOL 规范作了某些改编和扩充。故不同数据库管理系统之间的 SOL语言不能完全相互通用。

        以下是SQLite的一些关键特点:

  • 零配置: SQLite不需要安装或者管理服务器进程。启动一个使用SQLite的应用程序时,数据库文件会自动创建(如果尚不存在),并且直接通过程序访问。
  • 轻量级: SQLite的代码量小,资源消耗少,对硬件要求很低。这使得它非常适合资源有限的环境,如手机、平板电脑或微型设备。
  • 跨平台: SQLite兼容几乎所有主流的操作系统,包括Windows、Linux、Unix、Android、iOS等。
  • 服务器less: 由于SQLite是嵌入式的,没有单独运行的数据库服务器进程,数据直接存储在文件中。这简化了部署和维护过程。
  • 事务处理: SQLite支持ACID(原子性、一致性、隔离性、持久性)事务,确保数据的完整性。
  • SQL标准兼容: 虽然SQLite有自己的SQL方言,但它大体上遵循ANSI SQL标准,支持大多数标准SQL语句。
  • 单一文件存储: SQLite数据库完全存储在一个磁盘文件中,这使得备份和迁移数据库变得非常简单,只需复制该文件即可。
  • 动态类型: SQLite具有弱类型特性,允许更灵活的数据存储,但也可能需要开发者更加注意数据类型的处理。
  • 广泛使用: SQLite被许多应用程序和操作系统采用,包括浏览器(如Firefox)、操作系统组件、手机应用等,是世界上最广泛部署的数据库引擎之一。

        有个重要的点值得注意,SQLite 是不区分大小写的,但也有一些命令是大小写敏感的,比如 GLOB 和 glob 在 SQLite 的语句中有不同的含义。一般数据采用固定的静态数据类型,而 SOLite 采用的是动态数据类型,会根据存入值自动判断。

SQLite 存储类:SOLite 具有以下五种基本数据类型

(1)integer:带符号的整型(最多64位)。

(2)real:8字节表示的浮点类型。

(3)text:字符类型,支持多种编码(如 UTF-8、UTF-16),大小无限制。

(4)blob:任意类型的数据,大小无限制。 BLOB(binary large obiect)二进制大对象,使用二进制保存数据。

(5)null:表示空值

SQLite 亲和类型(Affinity)及类型名称

下表列出了当创建 SQLite3 表时可使用的各种数据类型名称,同时也显示了相应的亲和类型

数据类型

亲和类型

  • INT
  • INTEGER
  • TINYINT
  • SMALLINT
  • MEDIUMINT
  • BIGINT
  • UNSIGNED BIG INT
  • INT2
  • INT8

INTEGER

  • CHARACTER(20)
  • VARCHAR(255)
  • VARYING CHARACTER(255)
  • NCHAR(55)
  • NATIVE CHARACTER(70)
  • NVARCHAR(100)
  • TEXT
  • CLOB

TEXT

  • BLOB
  • 未指定类型

BLOB

  • REAL
  • DOUBLE
  • DOUBLE PRECISION
  • FLOAT

REAL

  • NUMERIC
  • DECIMAL(10,5)
  • BOOLEAN
  • DATE
  • DATETIME

NUMERIC

SQLite 语句:所有的 SQLite 语句可以以任何关键字开始,如 SELECT、INSERT、UPDATE、DELETE、ALTER、DROP 等,所有的语句以分号 ; 结束。

3、SQLite3基本语法

(1)、创建数据库

//打开数据库,如不存在则会创建数据库
int ret = sqlite3_open("project_data.db", &db);
if( ret )
{fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));exit(-1);
}
fprintf(stderr, "Opened database successfully\n");

(2)、创建表

//CREATE TABLE 告诉数据库系统创建一个新表的关键字。CREATE TABLE 语句后跟着表的唯一的名称或标识。
CREATE TABLE database_name.table_name(column1 datatype  PRIMARY KEY(one or more columns),column2 datatype,column3 datatype,.....columnN datatype,
);char table_name[200] = {0};
char *err_msg = NULL;
snprintf(table_name, sizeof(table_name), "create table if not exists camera(time_stamp integer primary key, action text, x integer, y integer, z integer, vx integer, vy integer, vz integer, time integer);");
int ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
if(ret){fprintf(stderr, "create table err:%s\n", err_msg);return -1;
}
fprintf(stderr, "create table successfully\n");

(3)、删除表

//SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据、索引、触发器、约束和该表的权限规范。
//DROP TABLE 语句的基本语法如下。
DROP TABLE database_name.table_name;char table_name[200] = {0};
char *err_msg = NULL;
snprintf(table_name, sizeof(table_name), "DROP TABLE database_name.table_name;");
int ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);
if(ret){fprintf(stderr, "delete table err:%s\n", err_msg);return -1;
}
fprintf(stderr, "delete table successfully\n");

(4)、插入数据

INSERT INTO 语句有两种基本语法,如下所示:
INSERT INTO TABLE_NAME [(column1, column2, column3,...columnN)]  VALUES (value1, value2, value3,...valueN);//在这里,column1, column2,...columnN 是要插入数据的表中的列的名称
或
INSERT INTO TABLE_NAME VALUES (value1,value2,value3,...valueN);
//确保值的顺序与列在表中的顺序一致。char table_value[200] = {0};
int ret = 0;
char *err_msg = NULL;
snprintf(table_value, sizeof(table_value),"insert into camera values(%lld, '%c', %d, %d, %d, %d, %d, %d, %d);", get_current_timestamp_ms(), action, x, y, z, vx, vy, vz, time);
ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);
if(ret)
{fprintf(stderr, "insert value to table err:%s\n", err_msg);return -1;
}
fprintf(stderr, "insert value to table successfully\n");

(5)、查询数据

//SQLite 的 SELECT 语句用于从 SQLite 数据库表中获取数据,以结果表的形式返回数据。这些结果表也被称为结果集。
//SQLite 的 SELECT 语句的基本语法如下:
SELECT column1, column2, columnN FROM table_name;//在这里,column1, column2...是表的字段,他们的值即是您要获取的。
SELECT * FROM table_name;    //获取所有可用的字段char *err_msg = NULL;
sprintf(sql, "select * from table_value;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{fprintf(stderr, "Can't select sqlite value: %s\n", sqlite3_errmsg(db));return -1;
}

(6)、删除数据

//SQLite 的 DELETE 查询用于删除表中已有的记录。可以使用带有 WHERE 子句的 DELETE 查询来删除选定行,否则所有的记录都会被删除。
//带有 WHERE 子句的 DELETE 查询的基本语法如下:
DELETE FROM table_name
WHERE [condition];
//可以使用 AND 或 OR 运算符来结合 N 个数量的条件。char *err_msg = NULL;
sprintf(sql, "DELETE FROM camera WHERE time_stamp = 123456789;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{fprintf(stderr, "Can't DELETE sqlite data: %s\n", sqlite3_errmsg(db));return -1;
}

(7)、修改数据

//SQLite 的 UPDATE 查询用于修改表中已有的记录。可以使用带有 WHERE 子句的 UPDATE 查询来更新选定行,否则所有的行都会被更新。
//带有 WHERE 子句的 UPDATE 查询的基本语法如下:
UPDATE table_name
SET column1 = value1, column2 = value2...., columnN = valueN
WHERE [condition];char *err_msg = NULL;
sprintf(sql, "UPDATE camera SET action = 't' WHERE time_stamp = 123456789;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //执行 SQL 命令的快捷方式
if(ret)
{fprintf(stderr, "Can't DELETE sqlite data: %s\n", sqlite3_errmsg(db));return -1;
}

4、SQLite3代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sqlite3.h>int database_init();
int write_motor_info_to_database(sqlite3 *db, int motor_id, double target_pos, double real_pos, double real_speed, double real_current);
int write_camera_info_to_database(sqlite3 *db, char action, int x, int y, int z, int vx, int vy, int vz, int time);
long long get_current_timestamp_ms(void); int main(void)
{printf("sqlite3 database test!\n");    database_init();return 0;
}/*** @brief  数据库初始化* @param  NONE* @retval 成功返回0, 失败返回-1*/
int database_init(void)  
{int ret = -1;sqlite3 *db;char *err_msg = NULL;char database_name[128] = {0};//获取当前时间struct tm t; time_t now;time(&now);localtime_s(&t, &now);snprintf(database_name, sizeof(database_name),"%02d%02d%02d.db", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);printf("date:%s\n", database_name);//打开数据库ret = sqlite3_open(database_name, &db);if( ret ){fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));return -1;}fprintf(stderr, "Opened database successfully\n");char table_name[200] = {0};//时间戳 目标位置 实际位置 实际速度 实际电流//create table if not exists motor0 (time_stamp integer primary key, target_pos real, real_pos real, real_speed real, real_current, real);for(int motor_id = 0; motor_id < 6; motor_id++){snprintf(table_name, sizeof(table_name),"create table if not exists motor%d (time_stamp integer primary key, target_pos real, real_pos real, real_speed real, real_current real);", motor_id);ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);if(ret){fprintf(stderr, "create table err:%s\n", err_msg);return -1;}fprintf(stderr, "create table successfully\n");}memset(table_name, 0, sizeof(table_name));snprintf(table_name, sizeof(table_name), "create table if not exists camera(time_stamp integer primary key, action text, x integer, y integer, z integer, vx integer, vy integer, vz integer, time integer);");ret = sqlite3_exec(db, table_name, NULL, NULL, &err_msg);if(ret){fprintf(stderr, "create table err:%s\n", err_msg);return -1;}fprintf(stderr, "create table successfully\n");write_motor_info_to_database(db, 0, 90.0, 87.2, 5.0, 0.85);write_motor_info_to_database(db, 1, 90.0, 87.2, 5.0, 0.85);write_motor_info_to_database(db, 2, 90.0, 87.2, 5.0, 0.85);write_motor_info_to_database(db, 3, 90.0, 87.2, 5.0, 0.85);write_motor_info_to_database(db, 4, 90.0, 87.2, 5.0, 0.85);write_motor_info_to_database(db, 5, 90.0, 87.2, 5.0, 0.85);write_camera_info_to_database(db, 't', 100,200,150,160,130,110,1000);return 0;
}/*** @brief  写入电机数据到数据库中* @param  db:数据库文件描述符* @param  target_pos:目标位置* @param  real_pos:实际位置* @param  real_speed:实际速度* @param  real_current:实际电流* @retval 写入成功返回0,失败-1*/
int write_motor_info_to_database(sqlite3 *db, int motor_id, double target_pos, double real_pos, double real_speed, double real_current)
{char table_value[200] = {0};int ret = 0;char *err_msg = NULL;//insert into motor0 values(1798345, 90.0, 88.66, 45.1, 0.97);snprintf(table_value, sizeof(table_value),"insert into motor%d values(%lld, %.2f, %.2f, %.2f, %.2f);", motor_id, get_current_timestamp_ms(), target_pos, real_pos, real_speed, real_current);ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);if(ret){fprintf(stderr, "insert value to table err:%s\n", err_msg);return -1;}fprintf(stderr, "insert value to table successfully\n");return 0;
}/*** @brief  写入相机数据到数据库中* @param  db:数据库文件描述符* @param  action:动作* @param  x:* @param  y:* @param  z:* @param  vx:* @param  vy:* @param  vz:* @retval 写入成功返回0,失败-1*/
int write_camera_info_to_database(sqlite3 *db, char action, int x, int y, int z, int vx, int vy, int vz, int time)
{char table_value[200] = {0};int ret = 0;char *err_msg = NULL;//insert into motor0 values(1798345, 90.0, 88.66, 45.1, 0.97);snprintf(table_value, sizeof(table_value),"insert into camera values(%lld, '%c', %d, %d, %d, %d, %d, %d, %d);", get_current_timestamp_ms(), action, x, y, z, vx, vy, vz, time);ret = sqlite3_exec(db, table_value, NULL, NULL, &err_msg);if(ret){fprintf(stderr, "insert value to table err:%s\n", err_msg);return -1;}fprintf(stderr, "insert value to table successfully\n");return 0;
}/*** @brief  获取毫秒级时间戳* @param  NONE* @retval 成功返回时间戳值,失败返回-1*/
long long get_current_timestamp_ms(void)
{
#if defined(_WIN32) || defined(_WIN64)struct _timeb timebuffer;_ftime64_s(&timebuffer);return (long long)timebuffer.time * 1000 + timebuffer.millitm;
#elif defined(__unix__) || defined(__unix) || defined(unix)struct timeval tv;gettimeofday(&tv, NULL);return (long long)tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}

参考代码运行结果

使用可视化工具SQLiteStudio,对SQLite3数据库进行查看。


http://www.ppmy.cn/embedded/39954.html

相关文章

0-1背包问题(回溯法)

#include<stdio.h> #define N 100 int n,W,bestp,maxw; int p[10000],w[10000],x[10000],bestx[10000]; int bound(int k){ //用来计算剩余物品的价值之和 int rp0;while(k<n){rprpp[k];k;}return rp; } void Backtrack(int i,int cp,int cw){int j;if(i>n)//回溯结…

新版Idea配置仓库教程

这里模拟的是自己搭建的本地仓库环境&#xff0c;基于虚拟机搭建利用gogs创建的仓库 1、Git环境 你需要准备好git和仓库可以使用github 、gitee等 1.1 拉取代码 本项目使用 Git 进行版本控制&#xff0c;在 gogs 上创建一个个人使用的 git 仓库&#xff1a; http://192.168.…

javax.net.ssl.SSLException: Received fatal alert: protocol_version已经解决

起因&#xff1a; 在帮别人讲解项目时&#xff0c;将项目的tomcat配置完&#xff0c;点击运行后&#xff0c;报错&#xff0c;信息如标题。 解决办法&#xff1a; 在csdn百度问题&#xff0c;得到的方法主要有几个&#xff1a; 1.jdk要配置在1.8以上&#xff1b; 2.数据库地…

Android 适配阿拉伯语之vector图标镜像

Android 适配阿拉伯语之vector图标镜像 android:autoMirrored“true” 属性简单而直接的方法来自动处理 RTL 环境中图标的翻转。 使用 android:autoMirrored“true” 在 Vector Drawable 中是一种非常方便的方法&#xff0c;因为它允许你使用相同的 drawable 资源来适应不同的…

WebSocket 详解加入门实操理解加深

WebSocket 介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短连接…

C++ list 介绍

&#x1f308;一、认识list这个模版 ist是一个模版&#xff0c;需要结合一个具体的数据类型作为模版参数&#xff0c; 即list < T > <T> <T>&#xff0c;才能成为一个类类型。list是双向循环链表&#xff0c;是序列容器&#xff0c;允许在序列中的任何位置进…

Openssl X509证书从HexStream中解析

整体思路 从hex 转换成字节流 然后从字节流中进行解析 You have access to the raw certificate in memory. In the case that you have access to the raw encoding of the certificate in memory, you can parse it as follows. This is useful if you have stored raw cer…

Electron学习笔记(四)

文章目录 相关笔记笔记说明 六、数据1、使用本地文件持久化数据(1) 用户数据目录(2) 读写本地文件(3) 第三方库 2、读写受限访问的 Cookie3、清空浏览器缓存 相关笔记 Electron学习笔记&#xff08;一&#xff09;Electron学习笔记&#xff08;二&#xff09;Electron学习笔记…

SQL中的LAG函数与LEAD函数用法

LAG&#xff1a;函数用于获取结果集中当前行之前的某一行的值 LAG (scalar_expression [,offset] [,default]) OVER ([partition_by_clause ] order_by_clause ) -----汉字解释 LAG (字段 [,偏移量默认为1] [,如果没有值时候默认值]) OVER ( [ partition_by 字段 ] order_by 字…

最新版Ceph( Reef版本)文件存储简单对接k8s(下集)

假如ceph集群已经创建 1.创建cephfs_pool存储池 ceph osd pool create fs_kube_data 16 162.创建cephfs_metadata存储池 ceph osd pool create fs_kube_metadata 16 163 创建cephfs ceph fs new cephfs01 fs_kube_metadata fs_kube_data4 设置最大活动数 ceph fs set cephfs01…

ShellCode详解三

直接进入正题。 在完成正式的shellcode代码导出之前&#xff0c;我们先手动的对代码进行导出&#xff0c;以使各位同学更加了解其原理。 手动注入shellcode 1、我们利用DLE工具找到上一节中我们生成的PE文件的代码段位置 上述图片就是我们的代码段位置 2、利用WinHex工具我…

探索全画面塑料焊接透光率检测仪的科技魅力

在精密工业和科研领域中&#xff0c;对材料的光学性能有着严格的要求。全画面塑料焊接透光率检测仪是一种先进的设备&#xff0c;它能够精确测量塑料焊接接头的透光率&#xff0c;确保焊接质量符合高标准。本文将详细介绍这一设备的特点、工作原理以及它在实际应用中的重要性。…

Docker停止不了

报错信息 意思是&#xff0c;docker.socket可能也会把docker服务启动起来 解决 检查服务状态 systemctl status dockersystemctl is-enabled docker停止docker.socket systemctl stop docker.socket停止docker systemctl stop docker知识扩展 安装了docker后&#xff0c;…

echarts图表x轴如何只显示起始数据和结束数据

实现效果 原效果 实现代码 let dataList [{date: 2022-01-22,type: 0,},{date: 2022-01-23,type: 5},{date: 2022-01-24,type: 2,},{date: 2022-01-25,type: 22,},{date: 2022-01-26,type: 0,},{date: 2022-01-27,type: 8},{date: 2022-01-28,type: 32,},{date: 2022-01-29,t…

WPS表格:使用vlookup函数解决乱序数据对应问题

我们常常会遇到两个表格的内容相同&#xff0c;但是顺序不一致的情况。并且这种顺序无关于简单的排序&#xff0c;而是一种业务性很强的复杂排序规则。下面我举个例子&#xff0c;使用VLOOKUP复制数据。 假设太阳系行星举办了一次卖萌比赛&#xff0c;由太阳妈妈决定谁是最萌的…

TMS320F280049 CLB模块--FSM(3)

功能框图 FSM有效状态机内部框图如下图所示&#xff0c;可以看到内部有S0 / S1两个状态和下一状态的跳转查找表。还有个输出查找表。 下图是FSM LUT的示意框图。FSM还可以工作在3输入或4输入的查找表模式下。对于输入&#xff0c;EXTRA_EXT_IN1/0可以替换S0/1。 寄存器 参考文…

React 第二十五章 React.memo

React.memo 是 React 提供的一个高阶组件&#xff0c;用于对函数组件进行性能优化。 React.memo 的源码实际上就是返回一个 PureComponent 组件&#xff1a; function memo(FuncComp){return class Memo extends PureComponent{render(){return <>{FuncComp(this.props…

地主发金币【python实现】

从前有一个地主&#xff0c;他雇佣了一位骑士护送一车货物&#xff0c;给出的酬劳是这样的&#xff0c;第一天给1比特币&#xff0c;第二天给2比特币&#xff0c;第三天给3比特币&#xff0c;以此类推进行给比特币…&#xff0c;现在地主准备了165枚比特币&#xff0c;请问地主…

Vue3响应式原理实现与track和trigger依赖收集和触发依赖

前言 Vue的响应式系统是基于数据劫持加发布订阅者模式实现的&#xff0c;数据响应式就是建立响应式数据与依赖的关系 (调用了响应式数据的操作之间的关系) vue2使用Object.defineProperty进行数据拦截,而Vue3使用Proxy进行数据拦截是es6中新加的api,比Object.defineProperty解…

记一次favicon.ico的折腾

某项目需要将前端和后台整合在一起 我也不知道为啥要整合 上面有要求就整呗 正常前端npm run build打包后 dist内会根据设置自动生成favicon.ico文件在根目录下 但由于前后端整合 需要打包后将图标放在dist下的static文件夹里 需要的效果 打包后 index.html里 <link rel&…