当前位置: 首页 > article >正文

数据库-SQLite

目录

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.kler.cn/a/556468.html

相关文章:

  • 为什么docker 容器有的没有PORTS
  • 长尾关键词优化三步法:提升SEO搜索排名实战
  • Linux基础 -- 中断子系统之级联中断
  • 【问题】Qt c++ 因编码问题解析json失败
  • 多环境日志管理:使用Logback与Logstash集成实现高效日志处理
  • 《炒股养家心法.pdf》 kimi总结
  • 腾讯云开源Deepseek-V3与R1大模型API免费使用 + Chatbox本地化部署指南:从零到一的AI探索之旅
  • stm32单片机个人学习笔记16(SPI通信协议)
  • 论文解读 | AAAI'25 Cobra:多模态扩展的大型语言模型,以实现高效推理
  • ZLG嵌入式笔记 | 为什么你的网卡工作会不正常?(中)
  • Mysql测试连接失败
  • 【Day45 LeetCode】图论问题 Ⅲ
  • 为什么要用 const 和 let,而不是 var?
  • 使用 Docker 部署 Apache Spark 集群教程
  • 2025寒假天梯训练7
  • Python应用算法之贪心算法理解和实践
  • [Android] Battery Guru - 手机电量管理优化
  • 【愚公系列】《Python网络爬虫从入门到精通》022-Splash的爬虫应用
  • 后“智驾平权”时代,谁为安全冗余和体验升级“买单”
  • 跳表的C语言实现