嵌入式數(shù)據(jù)庫(kù)SQLite?3配置使用講解
0、慘痛教訓(xùn)
隨著管理開(kāi)發(fā)的項(xiàng)目體積越來(lái)越龐大,產(chǎn)品系統(tǒng)涉及的數(shù)據(jù)量也越來(lái)越多,并且伴隨著項(xiàng)目不久就要交付給甲方了。如果項(xiàng)目的數(shù)據(jù)信息沒(méi)有被妥善管理,后期設(shè)備的運(yùn)行狀態(tài)、操作狀況等數(shù)據(jù)流信息不能被溯源,當(dāng)出現(xiàn)了一些特殊意外時(shí),就會(huì)導(dǎo)致對(duì)于故障信息不能迅速準(zhǔn)確的追蹤,甚至?xí)凰﹀?、推卸?zé)任,白白當(dāng)了冤大頭。因此對(duì)于嵌入式項(xiàng)目中,其產(chǎn)品運(yùn)行時(shí)的數(shù)據(jù)庫(kù)建立非常有必要,且是迫在眉睫?。?!
目前常用的數(shù)據(jù)庫(kù)系統(tǒng)有:MySQL、PostgreSQL、Oracle Database、Microsoft SQL Server、SQLite等。在嵌入式項(xiàng)目中,前面幾個(gè)數(shù)據(jù)庫(kù)顯然是不合適的,而SQLite是一個(gè)輕量級(jí)的數(shù)據(jù)庫(kù)管理系統(tǒng),它包含在一個(gè)C庫(kù)中,提供了零配置、無(wú)服務(wù)器、事務(wù)性的SQL數(shù)據(jù)庫(kù)引擎。所以SQLite的特點(diǎn)使其非常適合嵌入式系統(tǒng)、移動(dòng)設(shè)備、小型項(xiàng)目或者作為應(yīng)用程序的本地?cái)?shù)據(jù)庫(kù)使用。本文選用了嵌入式數(shù)據(jù)庫(kù)SQLite3進(jìn)行配置和講解。
1、Sqlite3環(huán)境配置
(1)、下載安裝SQLite庫(kù)
根據(jù)目標(biāo)系統(tǒng)平臺(tái),下載sqlite源碼,或下載官方提供的已經(jīng)編譯好的庫(kù)。本文目標(biāo)平臺(tái)是Windows11 64位平臺(tái),進(jìn)入SQLite Download Page的主頁(yè),選擇需要的庫(kù)版本(Windows)。

下載的壓縮包一共有如下所示的三個(gè):
sqlite-dll-win-x64-3450300.zip
sqlite-dll-win-x86-3450300.zip
sqlite-tools-win-x64-3450300.zip

(2)、解壓下載的文件
本文中將對(duì)應(yīng)的Sqlite庫(kù)文件解壓到了,C:\Program Files\sqlite路徑下。

(3)、添加庫(kù)路徑到環(huán)境變量
根據(jù)下圖所示的步驟,進(jìn)入系統(tǒng)屬性-->環(huán)境變量-->系統(tǒng)變量-->編輯環(huán)境變量,將路徑加入到環(huán)境變量中。

(4)、檢查數(shù)據(jù)庫(kù)安裝狀態(tài)
打開(kāi)Windows的命令行,輸入sqlite3,有類似如下的數(shù)據(jù)信息說(shuō)明庫(kù)安裝成功,后續(xù)只需在程序代碼中,將庫(kù)加入到工程代碼中即可。

(5)、SQLiteStudio工具
如果有可視化分析數(shù)據(jù)需求、推薦使用下載:SQLiteStudio

2、SQLite3基礎(chǔ)
SQL(Structured Query Language)是一種結(jié)構(gòu)化查詢語(yǔ)言,SQL 是一種專門(mén)用來(lái)與數(shù)據(jù)庫(kù)通信的語(yǔ)言。
不同的數(shù)據(jù)庫(kù)管理系統(tǒng)在其實(shí)踐過(guò)程中都對(duì) SOL 規(guī)范作了某些改編和擴(kuò)充。故不同數(shù)據(jù)庫(kù)管理系統(tǒng)之間的 SOL語(yǔ)言不能完全相互通用。
以下是SQLite的一些關(guān)鍵特點(diǎn):
- 零配置: SQLite不需要安裝或者管理服務(wù)器進(jìn)程。啟動(dòng)一個(gè)使用SQLite的應(yīng)用程序時(shí),數(shù)據(jù)庫(kù)文件會(huì)自動(dòng)創(chuàng)建(如果尚不存在),并且直接通過(guò)程序訪問(wèn)。
 - 輕量級(jí): SQLite的代碼量小,資源消耗少,對(duì)硬件要求很低。這使得它非常適合資源有限的環(huán)境,如手機(jī)、平板電腦或微型設(shè)備。
 - 跨平臺(tái): SQLite兼容幾乎所有主流的操作系統(tǒng),包括Windows、Linux、Unix、Android、iOS等。
 - 服務(wù)器less: 由于SQLite是嵌入式的,沒(méi)有單獨(dú)運(yùn)行的數(shù)據(jù)庫(kù)服務(wù)器進(jìn)程,數(shù)據(jù)直接存儲(chǔ)在文件中。這簡(jiǎn)化了部署和維護(hù)過(guò)程。
 - 事務(wù)處理: SQLite支持ACID(原子性、一致性、隔離性、持久性)事務(wù),確保數(shù)據(jù)的完整性。
 - SQL標(biāo)準(zhǔn)兼容: 雖然SQLite有自己的SQL方言,但它大體上遵循ANSI SQL標(biāo)準(zhǔn),支持大多數(shù)標(biāo)準(zhǔn)SQL語(yǔ)句。
 - 單一文件存儲(chǔ): SQLite數(shù)據(jù)庫(kù)完全存儲(chǔ)在一個(gè)磁盤(pán)文件中,這使得備份和遷移數(shù)據(jù)庫(kù)變得非常簡(jiǎn)單,只需復(fù)制該文件即可。
 - 動(dòng)態(tài)類型: SQLite具有弱類型特性,允許更靈活的數(shù)據(jù)存儲(chǔ),但也可能需要開(kāi)發(fā)者更加注意數(shù)據(jù)類型的處理。
 - 廣泛使用: SQLite被許多應(yīng)用程序和操作系統(tǒng)采用,包括瀏覽器(如Firefox)、操作系統(tǒng)組件、手機(jī)應(yīng)用等,是世界上最廣泛部署的數(shù)據(jù)庫(kù)引擎之一。
 
有個(gè)重要的點(diǎn)值得注意,SQLite 是不區(qū)分大小寫(xiě)的,但也有一些命令是大小寫(xiě)敏感的,比如 GLOB 和 glob 在 SQLite 的語(yǔ)句中有不同的含義。一般數(shù)據(jù)采用固定的靜態(tài)數(shù)據(jù)類型,而 SOLite 采用的是動(dòng)態(tài)數(shù)據(jù)類型,會(huì)根據(jù)存入值自動(dòng)判斷。
SQLite 存儲(chǔ)類:SOLite 具有以下五種基本數(shù)據(jù)類型
(1)integer:帶符號(hào)的整型(最多64位)。
(2)real:8字節(jié)表示的浮點(diǎn)類型。
(3)text:字符類型,支持多種編碼(如 UTF-8、UTF-16),大小無(wú)限制。
(4)blob:任意類型的數(shù)據(jù),大小無(wú)限制。 BLOB(binary large obiect)二進(jìn)制大對(duì)象,使用二進(jìn)制保存數(shù)據(jù)。
(5)null:表示空值
SQLite 親和類型(Affinity)及類型名稱
下表列出了當(dāng)創(chuàng)建 SQLite3 表時(shí)可使用的各種數(shù)據(jù)類型名稱,同時(shí)也顯示了相應(yīng)的親和類型:
數(shù)據(jù)類型  | 親和類型  | 
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 語(yǔ)句:所有的 SQLite 語(yǔ)句可以以任何關(guān)鍵字開(kāi)始,如 SELECT、INSERT、UPDATE、DELETE、ALTER、DROP 等,所有的語(yǔ)句以分號(hào) ; 結(jié)束。
3、SQLite3基本語(yǔ)法
(1)、創(chuàng)建數(shù)據(jù)庫(kù)
//打開(kāi)數(shù)據(jù)庫(kù),如不存在則會(huì)創(chuàng)建數(shù)據(jù)庫(kù)
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)、創(chuàng)建表
//CREATE TABLE 告訴數(shù)據(jù)庫(kù)系統(tǒng)創(chuàng)建一個(gè)新表的關(guān)鍵字。CREATE TABLE 語(yǔ)句后跟著表的唯一的名稱或標(biāo)識(shí)。
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 語(yǔ)句用來(lái)刪除表定義及其所有相關(guān)數(shù)據(jù)、索引、觸發(fā)器、約束和該表的權(quán)限規(guī)范。
//DROP TABLE 語(yǔ)句的基本語(yǔ)法如下。
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)、插入數(shù)據(jù)
INSERT INTO 語(yǔ)句有兩種基本語(yǔ)法,如下所示:
INSERT INTO TABLE_NAME [(column1, column2, column3,...columnN)]  VALUES (value1, value2, value3,...valueN);//在這里,column1, column2,...columnN 是要插入數(shù)據(jù)的表中的列的名稱
或
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)、查詢數(shù)據(jù)
//SQLite 的 SELECT 語(yǔ)句用于從 SQLite 數(shù)據(jù)庫(kù)表中獲取數(shù)據(jù),以結(jié)果表的形式返回?cái)?shù)據(jù)。這些結(jié)果表也被稱為結(jié)果集。
//SQLite 的 SELECT 語(yǔ)句的基本語(yǔ)法如下:
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);   //執(zhí)行 SQL 命令的快捷方式
if(ret)
{
    fprintf(stderr, "Can't select sqlite value: %s\n", sqlite3_errmsg(db));
    return -1;
}(6)、刪除數(shù)據(jù)
//SQLite 的 DELETE 查詢用于刪除表中已有的記錄??梢允褂脦в?WHERE 子句的 DELETE 查詢來(lái)刪除選定行,否則所有的記錄都會(huì)被刪除。
//帶有 WHERE 子句的 DELETE 查詢的基本語(yǔ)法如下:
DELETE FROM table_name
WHERE [condition];
//可以使用 AND 或 OR 運(yùn)算符來(lái)結(jié)合 N 個(gè)數(shù)量的條件。
char *err_msg = NULL;
sprintf(sql, "DELETE FROM camera WHERE time_stamp = 123456789;");
ret = sqlite3_exec(db, sql, NULL, NULL, &err_msg);   //執(zhí)行 SQL 命令的快捷方式
if(ret)
{
    fprintf(stderr, "Can't DELETE sqlite data: %s\n", sqlite3_errmsg(db));
    return -1;
}(7)、修改數(shù)據(jù)
//SQLite 的 UPDATE 查詢用于修改表中已有的記錄??梢允褂脦в?WHERE 子句的 UPDATE 查詢來(lái)更新選定行,否則所有的行都會(huì)被更新。
//帶有 WHERE 子句的 UPDATE 查詢的基本語(yǔ)法如下:
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);   //執(zhí)行 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  數(shù)據(jù)庫(kù)初始化
  * @param  NONE
  * @retval 成功返回0, 失敗返回-1
  */
int database_init(void)  
{
    int ret = -1;
    sqlite3 *db;
    char *err_msg = NULL;
    char database_name[128] = {0};
    //獲取當(dāng)前時(shí)間
    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);
   //打開(kāi)數(shù)據(jù)庫(kù)
    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};
    //時(shí)間戳 目標(biāo)位置 實(shí)際位置 實(shí)際速度 實(shí)際電流
    //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  寫(xiě)入電機(jī)數(shù)據(jù)到數(shù)據(jù)庫(kù)中
  * @param  db:數(shù)據(jù)庫(kù)文件描述符
  * @param  target_pos:目標(biāo)位置
  * @param  real_pos:實(shí)際位置
  * @param  real_speed:實(shí)際速度
  * @param  real_current:實(shí)際電流
  * @retval 寫(xiě)入成功返回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  寫(xiě)入相機(jī)數(shù)據(jù)到數(shù)據(jù)庫(kù)中
  * @param  db:數(shù)據(jù)庫(kù)文件描述符
  * @param  action:動(dòng)作
  * @param  x:
  * @param  y:
  * @param  z:
  * @param  vx:
  * @param  vy:
  * @param  vz:
  * @retval 寫(xiě)入成功返回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  獲取毫秒級(jí)時(shí)間戳
  * @param  NONE
  * @retval 成功返回時(shí)間戳值,失敗返回-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
}參考代碼運(yùn)行結(jié)果

使用可視化工具SQLiteStudio,對(duì)SQLite3數(shù)據(jù)庫(kù)進(jìn)行查看。

到此這篇關(guān)于嵌入式數(shù)據(jù)庫(kù)SQLite 3配置使用詳細(xì)筆記教程的文章就介紹到這了,更多相關(guān)嵌入式數(shù)據(jù)庫(kù)SQLite 3內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
 sqlite3 top的查詢及l(fā)imit語(yǔ)法介紹
sqlite3中沒(méi)有top的語(yǔ)法結(jié)構(gòu),不過(guò)相關(guān)的語(yǔ)法能實(shí)現(xiàn)跟top語(yǔ)法相同的功能,感興趣的你可以參考下,希望可以幫助到你2013-02-02
 sqlite時(shí)間戳轉(zhuǎn)時(shí)間語(yǔ)句(時(shí)間轉(zhuǎn)時(shí)間戳)
這篇文章主要介紹了sqlite時(shí)間戳轉(zhuǎn)時(shí)間、時(shí)間轉(zhuǎn)時(shí)間戳的方法,需要的朋友可以參考下2014-06-06
 SQLite教程(一):SQLite數(shù)據(jù)庫(kù)介紹
這篇文章主要介紹了SQLite教程(一):SQLite數(shù)據(jù)庫(kù)介紹,本文講解了什么是SQLite、SQLite的主要優(yōu)點(diǎn)、和RDBMS相比SQLite的一些劣勢(shì)、個(gè)性化特征等內(nèi)容,需要的朋友可以參考下2015-05-05
 Sqlite數(shù)據(jù)庫(kù)三種加密方法分析和實(shí)現(xiàn)
SQLite作為一個(gè)廣泛使用的數(shù)據(jù)庫(kù)引擎,其內(nèi)置加密和第三方庫(kù)加密方案如SQLCipher提供了保護(hù)數(shù)據(jù)安全和隱私的方法,本文詳細(xì)講解如何通過(guò)Himi加密方法實(shí)現(xiàn)SQLite數(shù)據(jù)的加密與解密,包括數(shù)據(jù)的加密預(yù)處理、安全存儲(chǔ)、查詢與解密過(guò)程2025-06-06
 VScode第三方插件打開(kāi)sqlite數(shù)據(jù)庫(kù)圖文教程
在實(shí)際做一個(gè)項(xiàng)目的時(shí)候,為了提高效率我們會(huì)首選不重復(fù)造輪子,所以可能會(huì)用到第三方庫(kù),下面這篇文章主要給大家介紹了關(guān)于VScode第三方插件打開(kāi)sqlite數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06
 SQLite學(xué)習(xí)手冊(cè)(SQLite在線備份)
在SQLite中提供了一組用于在線數(shù)據(jù)庫(kù)備份的APIs函數(shù)(C接口),可以很好的解決上述方法存在的不足。通過(guò)該組函數(shù),可以將源數(shù)據(jù)庫(kù)中的內(nèi)容拷貝到另一個(gè)數(shù)據(jù)庫(kù),同時(shí)覆蓋目標(biāo)數(shù)據(jù)庫(kù)中的數(shù)據(jù)2013-12-12
 SQLite 入門(mén)教程一 基本控制臺(tái)(終端)命令
SQLite 是一個(gè)自持的(self-contained)、無(wú)服務(wù)器的、零配置的、事務(wù)型的關(guān)系型數(shù)據(jù)庫(kù)引擎。因?yàn)樗苄?,所以也可以作為嵌入式?shù)據(jù)庫(kù)內(nèi)建在你的應(yīng)用程序中2013-12-12

