嵌入式數(shù)據(jù)庫SQLite?3配置使用講解
0、慘痛教訓
隨著管理開發(fā)的項目體積越來越龐大,產品系統(tǒng)涉及的數(shù)據(jù)量也越來越多,并且伴隨著項目不久就要交付給甲方了。如果項目的數(shù)據(jù)信息沒有被妥善管理,后期設備的運行狀態(tài)、操作狀況等數(shù)據(jù)流信息不能被溯源,當出現(xiàn)了一些特殊意外時,就會導致對于故障信息不能迅速準確的追蹤,甚至會被甩鍋、推卸責任,白白當了冤大頭。因此對于嵌入式項目中,其產品運行時的數(shù)據(jù)庫建立非常有必要,且是迫在眉睫!?。?/p>
目前常用的數(shù)據(jù)庫系統(tǒng)有:MySQL、PostgreSQL、Oracle Database、Microsoft SQL Server、SQLite等。在嵌入式項目中,前面幾個數(shù)據(jù)庫顯然是不合適的,而SQLite是一個輕量級的數(shù)據(jù)庫管理系統(tǒng),它包含在一個C庫中,提供了零配置、無服務器、事務性的SQL數(shù)據(jù)庫引擎。所以SQLite的特點使其非常適合嵌入式系統(tǒng)、移動設備、小型項目或者作為應用程序的本地數(shù)據(jù)庫使用。本文選用了嵌入式數(shù)據(jù)庫SQLite3進行配置和講解。
1、Sqlite3環(huán)境配置
(1)、下載安裝SQLite庫
根據(jù)目標系統(tǒng)平臺,下載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)、添加庫路徑到環(huán)境變量
根據(jù)下圖所示的步驟,進入系統(tǒng)屬性-->環(huán)境變量-->系統(tǒng)變量-->編輯環(huán)境變量,將路徑加入到環(huán)境變量中。
(4)、檢查數(shù)據(jù)庫安裝狀態(tài)
打開Windows的命令行,輸入sqlite3,有類似如下的數(shù)據(jù)信息說明庫安裝成功,后續(xù)只需在程序代碼中,將庫加入到工程代碼中即可。
(5)、SQLiteStudio工具
如果有可視化分析數(shù)據(jù)需求、推薦使用下載:SQLiteStudio
2、SQLite3基礎
SQL(Structured Query Language)是一種結構化查詢語言,SQL 是一種專門用來與數(shù)據(jù)庫通信的語言。
不同的數(shù)據(jù)庫管理系統(tǒng)在其實踐過程中都對 SOL 規(guī)范作了某些改編和擴充。故不同數(shù)據(jù)庫管理系統(tǒng)之間的 SOL語言不能完全相互通用。
以下是SQLite的一些關鍵特點:
- 零配置: SQLite不需要安裝或者管理服務器進程。啟動一個使用SQLite的應用程序時,數(shù)據(jù)庫文件會自動創(chuàng)建(如果尚不存在),并且直接通過程序訪問。
- 輕量級: SQLite的代碼量小,資源消耗少,對硬件要求很低。這使得它非常適合資源有限的環(huán)境,如手機、平板電腦或微型設備。
- 跨平臺: SQLite兼容幾乎所有主流的操作系統(tǒng),包括Windows、Linux、Unix、Android、iOS等。
- 服務器less: 由于SQLite是嵌入式的,沒有單獨運行的數(shù)據(jù)庫服務器進程,數(shù)據(jù)直接存儲在文件中。這簡化了部署和維護過程。
- 事務處理: SQLite支持ACID(原子性、一致性、隔離性、持久性)事務,確保數(shù)據(jù)的完整性。
- SQL標準兼容: 雖然SQLite有自己的SQL方言,但它大體上遵循ANSI SQL標準,支持大多數(shù)標準SQL語句。
- 單一文件存儲: SQLite數(shù)據(jù)庫完全存儲在一個磁盤文件中,這使得備份和遷移數(shù)據(jù)庫變得非常簡單,只需復制該文件即可。
- 動態(tài)類型: SQLite具有弱類型特性,允許更靈活的數(shù)據(jù)存儲,但也可能需要開發(fā)者更加注意數(shù)據(jù)類型的處理。
- 廣泛使用: SQLite被許多應用程序和操作系統(tǒng)采用,包括瀏覽器(如Firefox)、操作系統(tǒng)組件、手機應用等,是世界上最廣泛部署的數(shù)據(jù)庫引擎之一。
有個重要的點值得注意,SQLite 是不區(qū)分大小寫的,但也有一些命令是大小寫敏感的,比如 GLOB 和 glob 在 SQLite 的語句中有不同的含義。一般數(shù)據(jù)采用固定的靜態(tài)數(shù)據(jù)類型,而 SOLite 采用的是動態(tài)數(shù)據(jù)類型,會根據(jù)存入值自動判斷。
SQLite 存儲類:SOLite 具有以下五種基本數(shù)據(jù)類型
(1)integer:帶符號的整型(最多64位)。
(2)real:8字節(jié)表示的浮點類型。
(3)text:字符類型,支持多種編碼(如 UTF-8、UTF-16),大小無限制。
(4)blob:任意類型的數(shù)據(jù),大小無限制。 BLOB(binary large obiect)二進制大對象,使用二進制保存數(shù)據(jù)。
(5)null:表示空值
SQLite 親和類型(Affinity)及類型名稱
下表列出了當創(chuàng)建 SQLite3 表時可使用的各種數(shù)據(jù)類型名稱,同時也顯示了相應的親和類型:
數(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 語句:所有的 SQLite 語句可以以任何關鍵字開始,如 SELECT、INSERT、UPDATE、DELETE、ALTER、DROP 等,所有的語句以分號 ; 結束。
3、SQLite3基本語法
(1)、創(chuàng)建數(shù)據(jù)庫
//打開數(shù)據(jù)庫,如不存在則會創(chuàng)建數(shù)據(jù)庫 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ù)庫系統(tǒng)創(chuàng)建一個新表的關鍵字。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 語句用來刪除表定義及其所有相關數(shù)據(jù)、索引、觸發(fā)器、約束和該表的權限規(guī)范。 //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)、插入數(shù)據(jù)
INSERT INTO 語句有兩種基本語法,如下所示: 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 語句用于從 SQLite 數(shù)據(jù)庫表中獲取數(shù)據(jù),以結果表的形式返回數(shù)據(jù)。這些結果表也被稱為結果集。 //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); //執(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 查詢來刪除選定行,否則所有的記錄都會被刪除。 //帶有 WHERE 子句的 DELETE 查詢的基本語法如下: DELETE FROM table_name WHERE [condition]; //可以使用 AND 或 OR 運算符來結合 N 個數(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 查詢來更新選定行,否則所有的行都會被更新。 //帶有 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); //執(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ù)庫初始化 * @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); //打開數(shù)據(jù)庫 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 寫入電機數(shù)據(jù)到數(shù)據(jù)庫中 * @param db:數(shù)據(jù)庫文件描述符 * @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 寫入相機數(shù)據(jù)到數(shù)據(jù)庫中 * @param db:數(shù)據(jù)庫文件描述符 * @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數(shù)據(jù)庫進行查看。
到此這篇關于嵌入式數(shù)據(jù)庫SQLite 3配置使用詳細筆記教程的文章就介紹到這了,更多相關嵌入式數(shù)據(jù)庫SQLite 3內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SQLite教程(一):SQLite數(shù)據(jù)庫介紹
這篇文章主要介紹了SQLite教程(一):SQLite數(shù)據(jù)庫介紹,本文講解了什么是SQLite、SQLite的主要優(yōu)點、和RDBMS相比SQLite的一些劣勢、個性化特征等內容,需要的朋友可以參考下2015-05-05Sqlite數(shù)據(jù)庫三種加密方法分析和實現(xiàn)
SQLite作為一個廣泛使用的數(shù)據(jù)庫引擎,其內置加密和第三方庫加密方案如SQLCipher提供了保護數(shù)據(jù)安全和隱私的方法,本文詳細講解如何通過Himi加密方法實現(xiàn)SQLite數(shù)據(jù)的加密與解密,包括數(shù)據(jù)的加密預處理、安全存儲、查詢與解密過程2025-06-06VScode第三方插件打開sqlite數(shù)據(jù)庫圖文教程
在實際做一個項目的時候,為了提高效率我們會首選不重復造輪子,所以可能會用到第三方庫,下面這篇文章主要給大家介紹了關于VScode第三方插件打開sqlite數(shù)據(jù)庫的相關資料,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-06-06