平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“嵌入式数据库SQLite 3配置采用讲解”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
实际处理时,随着管理开发的项目体积越来越庞大,产品系统涉及的数据量也越来越多,同时且伴随着项目不久就要交付给甲方了。如果项目的数据信息没有被妥善管理,后期设备的运行状态、操作状况等数据流信息不能被溯源,当出现了一些特殊意外时,就会导致对于故障信息不能迅速准确的追踪,甚至会被甩锅、推卸责任,白白当了冤大头。因此对于嵌入式项目中,其产品运行时的数据库建立很有必要,且是迫在眉睫!!!
目前常用的数据库系统有:MySQL、PostgreSQL、Oracle Database、Microsoft SQL Server、SQLite等。在嵌入式项目中,前面几个数据库显然是不合适的,而SQLite是一个轻量级的数据库管理系统,它包含在一个C库中,提供了零设置、无服务器、事务性的SQL数据库引擎。所以SQLite的特点使其很适合嵌入式系统、移动设备、小型项目或者作为应用程序的本地数据库采用。本文选用了嵌入式数据库SQLite3进行设置和讲解。
从实现思路看,根据目标系统平台,下载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

本下文将对应的Sqlite库文件解压到了,C:Program Filessqlite路径下。
落到代码里,根据下图所示的步骤,进入系统属性-->环境变量-->系统变量-->编辑环境变量,将路径加入到环境变量中。

落到代码里,打开Windows的命令行,输入sqlite3,有类似如下所示的数据信息说明库安装成功,后续只需在程序代码中,将库加入到工程代码中即可。
如果有可视化分析数据需求、建议采用下载:SQLiteStudio
(链接已移除)

理解这一步时,SQL(Structured Query Language)是一种结构化查询语言,SQL 是一种专门用来与数据库通信的语言。
实际处理时,不同的数据库管理系统在其实践过程中都对 SOL 规范作了某些改编和扩充。故不同数据库管理系统之间的 SOL语言不能完全相互通用。
以下是SQLite的一些关键特点:
从实现思路看,有个重要的点值得注意,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 等,所有的语句以分号 ; 结束。
//打开数据库,如不存在则会创建数据库
int ret = sqlite3_open("project_data.db", &db);
if( ret )
{
fprintf(stderr, "Can't open database: %sn", sqlite3_errmsg(db));
exit(-1);
}
fprintf(stderr, "Opened database successfullyn");
//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:%sn", err_msg);
return -1;
}
fprintf(stderr, "create table successfullyn");
//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:%sn", err_msg);
return -1;
}
fprintf(stderr, "delete table successfullyn");
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:%sn", err_msg);
return -1;
}
fprintf(stderr, "insert value to table successfullyn");
//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: %sn", sqlite3_errmsg(db));
return -1;
}
//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: %sn", sqlite3_errmsg(db));
return -1;
}
//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: %sn", sqlite3_errmsg(db));
return -1;
}
#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:%sn", database_name);
//打开数据库
ret = sqlite3_open(database_name, &db);
if( ret )
{
fprintf(stderr, "Can't open database: %sn", sqlite3_errmsg(db));
return -1;
}
fprintf(stderr, "Opened database successfullyn");
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:%sn", err_msg);
return -1;
}
fprintf(stderr, "create table successfullyn");
}
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:%sn", err_msg);
return -1;
}
fprintf(stderr, "create table successfullyn");
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:%sn", err_msg);
return -1;
}
fprintf(stderr, "insert value to table successfullyn");
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:%sn", err_msg);
return -1;
}
fprintf(stderr, "insert value to table successfullyn");
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数据库进行查看。

到此这篇关于嵌入式数据库SQLite 3设置采用详细笔记教程的文章就介绍到这了,更多相关嵌入式数据库SQLite 3内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!