数据库-SQLite

news/2025/2/22 19:17:07

目录

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 1024

typedef 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.niftyadmin.cn/n/5862674.html

相关文章

JavaScript系列(79)--Web Worker 高级应用

Web Worker 高级应用 &#x1f504; Web Worker 为JavaScript提供了真正的多线程能力&#xff0c;让我们能够在后台线程中执行复杂的计算而不阻塞主线程。今天让我们深入探讨Web Worker的高级应用。 Web Worker 概述 &#x1f31f; &#x1f4a1; 小知识&#xff1a;Web Work…

在PyTorch中使用插值法来优化卷积神经网络(CNN)所需硬件资源

插值法其实就是在已知数据点之间估计未知点的值。通过已知的离散数据点,构造一个连续的曲线函数,预测数据点之间的空缺值是什么并且自动填补上去。 适用场景: 在卷积神经网络(CNN)中的应用场景中,经常遇到计算资源有限,比如显存不够或者处理速度慢,需要用插值来降低计…

设计模式之装饰器设计模式/包装设计模式

装饰器设计模式&#xff08;Decorator Pattern&#xff09; 也叫包装设计模式&#xff0c;属于结构型模式&#xff0c;它是作为现有的类的一个包装&#xff0c;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构 给对象增加功能&#xff0c;一般两种方式&#…

软考—系统架构设计(案例 | 论文)

系统设计&#xff08;案例&#xff5c;论文&#xff09; 系统设计是系统分析的延伸与拓展。系统分析阶段解决“做什么”的问题&#xff0c;而系统设计阶段解决“怎么做”的问题。 概要设计 系统设计的主要内容包括概要设计和详细设计。概要设计又称为系统总体结构设计&#…

如何成为一名合格的单片机工程师----引言介绍篇(1)

前言 在当今数字化时代&#xff0c;单片机&#xff08;Microcontroller Unit&#xff0c;MCU&#xff09;已成为电子设备的核心组件之一&#xff0c;广泛应用于智能家居、工业自动化、汽车电子、物联网等领域。作为一名单片机工程师&#xff0c;你将有机会参与到各种创新项目中…

代码随想录算法训练day62---图论系列6《并查集2》

代码随想录算法训练 —day62 文章目录 代码随想录算法训练前言一、108.冗余连接二、109. 冗余连接II总结 前言 今天是算法营的第62天&#xff0c;希望自己能够坚持下来&#xff01; 今天继续并查集系列&#xff01;今日任务&#xff1a; ● 108.冗余连接 ● 109.冗余连接II 一…

【SPIE出版,见刊快速,EI检索稳定,浙江水利水电学院主办】2025年物理学与量子计算国际学术会议(ICPQC 2025)

2025年物理学与量子计算国际学术会议&#xff08;ICPQC 2025&#xff09;将于2025年4月18-20日在中国杭州举行。本次会议旨在汇聚全球的研究人员、学者和业界专家&#xff0c;共同探讨物理学与量子计算领域的最新进展与前沿挑战。随着量子技术的快速发展&#xff0c;其在信息处…

安装 redis 5.0.14 版本

下载 gcc rpm 包 在能上网的服务器下执行如下命令下载安装包 $> yum install --downloadonly --downloaddir/DATA/soft/temp gcc 或使用如下命令下载 # 安装yum-utils $ yum -y install yum-utils # 下载 gcc 依赖包 $ yumdownloader --resolve --destdir/rpm gcc # 参数…