数据库-SQLite

news/2025/2/23 0:59:14/

目录

1.SQLite介绍

2.SQLite特性

3.SQLite使用

3.1.环境准备

3.2.创建数据库文件

3.3.操作数据库

4.API接口

4.1.封装数据库句柄结构体

4.2.数据库句柄初始化

4.3.连接数据库

4.4.创建表 插入数据 修改数据 删除数据

4.5.执行查询语句

4.6.初始化存储查询结果句柄

4.7.获取每一行查询结果

4.8.释放查询结果集

5.完整代码

6.总结


1.SQLite介绍

        SQLite 是一个轻量级的关系型数据库管理系统(RDBMS),广泛应用于桌面应用程序、移动设备和小型服务端应用中。它的主要特点是不需要一个独立的数据库服务器,而是通过嵌入到应用程序中运行。SQLite 使用一个简单的数据库文件存储所有数据,因此可以方便地进行数据的传输和备份。它支持 ACID(原子性、一致性、隔离性、持久性)事务,保证数据的可靠性。

2.SQLite特性

        优点:不需要配置、数据库文件小、支持跨平台、支持标准 SQL,并且非常适合用于嵌入式系统和低并发的应用。它在移动设备和桌面应用程序中非常流行,尤其是作为本地存储的数据库解决方案。在SQLite中,一个文件可以类似的看成MySQL中的数据库,即一个文件就是一个数据库。

        缺点:不适合高并发的应用、对于大规模数据处理可能性能不如 MySQL、PostgreSQL。

3.SQLite使用

3.1.环境准备

        需要安装sqlite3相关的安装包,参考ubuntu命令:apt-get install sqlite3 libsqlite3-dev

3.2.创建数据库文件

        使用 vim 在任意目录创建一个文件,后缀名没有要求,例如:vim test.sql

3.3.操作数据库

        创建好文件之后就可以操作该数据库了,例如:sqlite3 test.sql

        之后便可以创建表,然后进行增删改查操作。

4.API接口

4.1.封装数据库句柄结构体

typedef struct _DBHandle {sqlite3 *db;sqlite3_stmt *stmt;char **res;int column_num;
}DBHandle;

        db:sqlite3自带的数据库处理句柄

        stmt:sqlite3保存查询句柄

        res:用于保存查询结果的每一行

        column_num:查询结果的列数

        注:此结构体可以根据实际调整,具体为什么要这样实现可以参考MySql的机制。

4.2.数据库句柄初始化

        初始化只需要将数据库句柄赋值为0即可。

/* 数据库句柄初始化 */
void db_sqlite_init(DBHandle *db_handle) {memset(db_handle, 0, sizeof(DBHandle));return;
}

4.3.连接数据库

        连接数据库即打开sqlite3数据库文件的过程,调用sqlite3原生接口。

SQLITE_API int sqlite3_open(const char *filename,   /* Database filename (UTF-8) */sqlite3 **ppDb          /* OUT: SQLite db handle */
);/* 连接数据库 */
int db_sqlite_connect(DBHandle *db_handle, const char *file_name) {int result = sqlite3_open(file_name, &db_handle->db);if (result != SQLITE_OK) {printf("Can't open database: %s\n", sqlite3_errmsg(db_handle->db));return DB_FAILED;}return DB_SUCCESS;
}

4.4.创建表 插入数据 修改数据 删除数据

        创建表 插入数据 修改数据 删除数据不需要获取查询结果,调用sqlite3操作sql语句的接口即可。

SQLITE_API int sqlite3_exec(sqlite3*,                                  /* An open database */const char *sql,                           /* SQL to be evaluated */int (*callback)(void*,int,char**,char**),  /* Callback function */void *,                                    /* 1st argument to callback */char **errmsg                              /* Error msg written here */
);/* 创建表 插入数据 修改数据 删除数据 */
int db_sqlite_execute(DBHandle *db_handle, const char *sql) {char *err_msg = NULL;int result = sqlite3_exec(db_handle->db, sql, 0, 0, &err_msg);if (result != SQLITE_OK) {printf("Failed execute sql, errmsg: %s.", err_msg);sqlite3_free(err_msg);return DB_FAILED;}return DB_SUCCESS;
}

4.5.执行查询语句

        执行查询语句需要传递 stmt 参数,同时调用sqlite3接口sqlite3_prepare_v2

SQLITE_API int sqlite3_prepare_v2(sqlite3 *db,            /* Database handle */const char *zSql,       /* SQL statement, UTF-8 encoded */int nByte,              /* Maximum length of zSql in bytes. */sqlite3_stmt **ppStmt,  /* OUT: Statement handle */const char **pzTail     /* OUT: Pointer to unused portion of zSql */
);/* 执行查询语句 */
int db_sqlite_query(DBHandle *db_handle, const char *sql) {int result = sqlite3_prepare_v2(db_handle->db, sql, -1, &db_handle->stmt, 0);if (result != SQLITE_OK) {printf("Failed to prepare statement: %s\n", sqlite3_errmsg(db_handle->db));return DB_FAILED;}return DB_SUCCESS;
}

4.6.初始化存储查询结果句柄

        初始话查询结果句柄 res,其实就是给 res 分配内存空间,用于保存每一行的查询结果。

/* 初始化存储查询结果句柄 */
int db_sqlite_fetch_init(DBHandle *db_handle) {db_handle->column_num = sqlite3_column_count(db_handle->stmt);db_handle->res = (char **)malloc(sizeof(char *) * db_handle->column_num );if (!db_handle->res) {printf("Failed to malloc memory for db_handle->res.");return DB_FAILED;}memset(db_handle->res, 0, sizeof(char *) * db_handle->column_num );return DB_SUCCESS;
}

4.7.获取每一行查询结果

        获取每一行查询结果,循环调用 sqlite3_step 函数,直到没有数据为止。

        注:此处为了方便统一接口,均返回char *(字符串类型),用户根据列属性自行转换。

SQLITE_API int sqlite3_step(sqlite3_stmt*);SQLITE_API const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);/* 获取每一行查询结果 */
char **db_sqlite_fetch_data(DBHandle *db_handle) {if (!db_handle->stmt) {return NULL;}if ((sqlite3_step(db_handle->stmt)) == SQLITE_ROW) {for (int i = 0; i < db_handle->column_num; i++) {db_handle->res[i] = (char *)sqlite3_column_text(db_handle->stmt, i);}return db_handle->res;}return NULL;
}

4.8.释放查询结果集

        释放查询结果集主要分两部分,一部分是释放申请的 res 内存,另外一部分是释放sqlite3使用的 stmt。

        注:为什么要这样设计可以参考MySql实现

SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);/* 释放查询结果集 */
void db_sqlite_fetch_free(DBHandle *db_handle) {if (db_handle->res) {free(db_handle->res);}sqlite3_finalize(db_handle->stmt);
}

5.完整代码

注:编译时需要链接sqlite3动态库

#include <stdio.h>
#include <sqlite3.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>#define DB_FAILED   -1
#define DB_SUCCESS  0#define MAX_SQL_LEN 1024typedef struct _DBHandle {sqlite3 *db;sqlite3_stmt *stmt;char **res;int column_num;
}DBHandle;/* 数据库句柄初始化 */
void db_sqlite_init(DBHandle *db_handle) {memset(db_handle, 0, sizeof(DBHandle));return;
}/* 连接数据库 */
int db_sqlite_connect(DBHandle *db_handle, const char *file_name) {int result = sqlite3_open(file_name, &db_handle->db);if (result != SQLITE_OK) {printf("Can't open database: %s\n", sqlite3_errmsg(db_handle->db));return DB_FAILED;}return DB_SUCCESS;
}/* 创建表 插入数据 修改数据 删除数据 */
int db_sqlite_execute(DBHandle *db_handle, const char *sql) {char *err_msg = NULL;int result = sqlite3_exec(db_handle->db, sql, 0, 0, &err_msg);if (result != SQLITE_OK) {printf("Failed execute sql, errmsg: %s.", err_msg);sqlite3_free(err_msg);return DB_FAILED;}return DB_SUCCESS;
}/* 插入数据 */
int insert_data(DBHandle *db_handle, const char *name, int age) {char sql[MAX_SQL_LEN] = {0};sqlite3_stmt *stmt;snprintf(sql, (size_t)MAX_SQL_LEN, "INSERT INTO users (name, age) VALUES (\"%s\", %d);", name, age);printf("sql:%s\n", sql);return db_sqlite_execute(db_handle, sql);
}/* 执行查询语句 */
int db_sqlite_query(DBHandle *db_handle, const char *sql) {int result = sqlite3_prepare_v2(db_handle->db, sql, -1, &db_handle->stmt, 0);if (result != SQLITE_OK) {printf("Failed to prepare statement: %s\n", sqlite3_errmsg(db_handle->db));return DB_FAILED;}return DB_SUCCESS;
}/* 初始化存储查询结果句柄 */
int db_sqlite_fetch_init(DBHandle *db_handle) {db_handle->column_num = sqlite3_column_count(db_handle->stmt);db_handle->res = (char **)malloc(sizeof(char *) * db_handle->column_num );if (!db_handle->res) {printf("Failed to malloc memory for db_handle->res.");return DB_FAILED;}memset(db_handle->res, 0, sizeof(char *) * db_handle->column_num );return DB_SUCCESS;
}/* 获取每一行查询结果 */
char **db_sqlite_fetch_data(DBHandle *db_handle) {if (!db_handle->stmt) {return NULL;}if ((sqlite3_step(db_handle->stmt)) == SQLITE_ROW) {for (int i = 0; i < db_handle->column_num; i++) {db_handle->res[i] = (char *)sqlite3_column_text(db_handle->stmt, i);}return db_handle->res;}return NULL;
}/* 释放查询结果集 */
void db_sqlite_fetch_free(DBHandle *db_handle) {if (db_handle->res) {free(db_handle->res);}sqlite3_finalize(db_handle->stmt);
}/* 查询users表数据 */
int query_users(DBHandle *db_handle) {const char *sql = "SELECT * FROM users;";if (db_sqlite_query(db_handle, sql) != DB_SUCCESS) {return DB_FAILED;}if (db_sqlite_fetch_init(db_handle) != DB_SUCCESS) {return DB_FAILED;}while (db_sqlite_fetch_data(db_handle)) {printf("ID: %d, Name: %s, Age: %d\n", atoi(db_handle->res[0]), db_handle->res[1], atoi(db_handle->res[2]));}db_sqlite_fetch_free(db_handle);return DB_SUCCESS;
}/* 更新users表数据 */
int update_users(DBHandle *db_handle, const char *name, int age, int id) {char sql[MAX_SQL_LEN] = {0};sqlite3_stmt *stmt;snprintf(sql, (size_t)MAX_SQL_LEN, "UPDATE users SET name = \"%s\", age = %d WHERE id = %d;", name, age, id);return db_sqlite_execute(db_handle, sql);
}/* 删除users表数据 */
int delete_users(DBHandle *db_handle, const char *name) {char sql[MAX_SQL_LEN] = {0};sqlite3_stmt *stmt;snprintf(sql, (size_t)MAX_SQL_LEN, "DELETE FROM users WHERE name = \"%s\";", name);return db_sqlite_execute(db_handle, sql);
}int main() 
{DBHandle db_hanle;db_sqlite_init(&db_hanle);db_sqlite_connect(&db_hanle, "./test.db");/* 建表 */if (db_sqlite_execute(&db_hanle, "CREATE TABLE IF NOT EXISTS users (""id INTEGER PRIMARY KEY AUTOINCREMENT,""name TEXT NOT NULL,""age INTEGER NOT NULL);")) {sqlite3_close(db_hanle.db);return DB_FAILED;}/* 插入数据 */if (insert_data(&db_hanle, "Tom", 25) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}/* 插入数据 */if (insert_data(&db_hanle, "Jerry", 30) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}printf("Users:\n");if (query_users(&db_hanle) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}if (update_users(&db_hanle, "Jack", 18, 1) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}printf("\nAfter Update:\n");if (query_users(&db_hanle) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}if (delete_users(&db_hanle, "Jerry") != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}printf("\nAfter Delete:\n");if (query_users(&db_hanle) != DB_SUCCESS) {sqlite3_close(db_hanle.db);return DB_FAILED;}sqlite3_close(db_hanle.db);return 0;
}

运行结果:

6.总结

         SQLite 是一个轻量级的嵌入式关系型数据库管理系统,它不依赖独立的服务器进程,而是直接嵌入到应用程序中。SQLite 通过一个文件存储整个数据库,所有的数据、表、索引和视图都保存在这个文件里。简单、易用、无需配置、占用资源少、支持跨平台。


http://www.ppmy.cn/news/1574285.html

相关文章

【Gin-Web】Bluebell社区项目梳理2:JWT-Token认证

本文目录 一、JWTHeaderPayloadSignature 二、代码解析刷新Token鉴权中间件 一、JWT JWT是Json Web Token的缩写。JWT本身是没有定义任何技术实现&#xff0c;只是定义了一种基于Token的会话管理规则&#xff0c;涵盖Token需要包含的标准内容和Token生成过程&#xff0c;特别适…

Rust 中的 `Drop` 特性:自动化资源清理的魔法

一、自动清理机制&#xff1a;Rust 的析构函数 在许多语言中&#xff0c;当程序结束或对象不再需要时&#xff0c;开发者必须显式调用清理函数来释放内存或关闭资源。Rust 则不然——它通过 Drop 特性实现了类似析构函数&#xff08;destructor&#xff09;的自动化清理机制。…

毕业项目推荐:基于yolov8/yolo11的100种中药材检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

缺少网络安全组织架构 网络安全缺陷

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 目录 TCP/IP概述 一、计算机网络的体系结构 1、计算机网络体系结构定义 2、OSI/RM与TCP/IP对应关系 3、名词释义 4、TCP/IP协议主要构成和功能 5、各层次间…

视频HDR技术详解,你的电脑怎么播放HDR视频?

闲聊&#xff1a;前两天在b站上面看到影视飓风的视频&#xff0c;让我有点疑惑&#xff0c;我不知道为什么播放视频有设备撑不住一说&#xff0c;所以感兴趣去ytb下载了4k原片30hz刷新的&#xff0c;然后测试一下我的电脑能不能播放&#xff0c;发现还是可以的&#xff0c;视觉…

【Rust中级教程】1.16. 泛型trait:泛型(类型参数)trait、关联类型trait

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 这篇文章以概念性的和建议性的文字偏多&#xff0c;需要你对泛型类型参数和关联类型有一定了…

【数据库系统概论】第第12章 并发控制

12.1 并发控制概述 并发控制是指数据库管理系统&#xff08;DBMS&#xff09;通过控制多个事务同时执行&#xff0c;保证数据的一致性和隔离性&#xff0c;避免事务间的相互干扰。 事务串行执行不能充分利用系统资源 并发执行的优点&#xff1a;能够减少处理机的空闲 时间&a…

【Gee】7天用 Go 从零实现 Web 框架 Gee

7天用 Go 从零实现 Web 框架 Gee 设计一个框架 在设计一个框架之前&#xff0c;我们需要回答框架核心为我们解决了什么问题。只有理解了这一点&#xff0c;才能想明白我们需要在框架当中实现什么功能。 首先我们来看一下标准库 net/http 如何处理一个请求&#xff1a; func…