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工具
如果有可视化分析数据需求、保举使用下载:SQLiteStudiohttps://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
|
- 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数据库进行查看。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |