第三方库介绍——SQLite3

文章目录

  • [1. 什么是 SQLite](#1. 什么是 SQLite)
  • [2. 为什么要用 SQLite](#2. 为什么要用 SQLite)
  • [3. SQLite3 C/C++ API 介绍](#3. SQLite3 C/C++ API 介绍)
  • [4. SQLite3 C/C++ API 使用](#4. SQLite3 C/C++ API 使用)

1. 什么是 SQLite

SQLite 是一个进程内的轻量级数据库,它实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,我们不需要在系统中配置。像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接,SQLite 直接访问其存储文件


2. 为什么要用 SQLite

  • 不需要一个单独的服务器进程或操作的系统(无服务器的)
  • SQLite 不需要配置
  • 一个完整的 SQLite 数据库是存储在一个单一的跨平台的磁盘文件
  • SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于 250KiB
  • SQLite 是自给自足的,这意味着不需要任何外部的依赖
  • SQLite 事务是完全兼容 ACID 的,允许从多个进程或线程安全访问
  • SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能
  • SQLite 使用 ANSI-C 编写的,并提供了简单和易于使用的 API
  • SQLite 可在 UNIX(Linux, Mac OS-X, Android, iOS)和 Windows(Win32, WinCE, WinRT)中运行

3. SQLite3 C/C++ API 介绍

C/C++ API 是 SQLite3 数据库的一个客户端, 提供一种用 C/C++操作数据库的方法。

SQLite3 官方文档:https://www.sqlite.org/c3ref/funclist.html

下面我们介绍一下常见的几个接口:

cpp 复制代码
sqlite3 操作流程:
0. 查看当前数据库在编译阶段是否启动了线程安全
int sqlite3_threadsafe(); 0-未启用; 1-启用
	需要注意的是 sqlite3 是有三种安全等级的:
	1. 非线程安全模式
	2. 线程安全模式(不同的连接在不同的线程/进程间是安全的,即一个
	句柄不能用于多线程间)
	3. 串行化模式(可以在不同的线程/进程间使用同一个句柄)
1. 创建/打开数据库文件,并返回操作句柄
	int sqlite3_open(const char *filename, sqlite3 **ppDb) 成功返回SQLITE_OK
	//若在编译阶段启动了线程安全,则在程序运行阶段可以通过参数选择线程安全等级
	int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
	flag: 
		SQLITE_OPEN_READWRITE -- 以可读可写方式打开数据库文件
		SQLITE_OPEN_CREATE -- 不存在数据库文件则创建
		SQLITE_OPEN_NOMUTEX--多线程模式,只要不同的线程使用不同的连接即可保证线程安全
		SQLITE_OPEN_FULLMUTEX--串行化模式
	zVfs:
		此参数允许指定一个自定义的虚拟文件系统实现,用于适应特殊的存储环境(如加密文件系统、网络存储等)。
		绝大多数情况下,传入 NULL使用默认的系统 VFS 即可。
	返回:SQLITE_OK 表示成功
2. 执行语句
	int sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*,int,char**,char**), 
void* arg, char **err)
	int (*callback)(void*,int,char**,char**)
		void* : 是设置的在回调时传入的 arg 参数
		int:一行中数据的列数
		char**:存储一行数据的字符指针数组
		char**:每一列的字段名称
		这个回调函数有个 int 返回值,成功处理的情况下必须返回 0,返回非 0 会触发 ABORT 退出程序
	返回:SQLITE_OK 表示成功
3. 销毁句柄
	int sqlite3_close(sqlite3* db); 成功返回 SQLITE_OK
	int sqlite3_close_v2(sqlite3*); 推荐使用--无论如何都会返回SQLITE_OK
获取错误信息
	const char *sqlite3_errmsg(sqlite3* db);

4. SQLite3 C/C++ API 使用

下面我们将这几个接口封装成一个类,快速上手这几个接口

cpp 复制代码
/*
    封装实现一个SqliteHelper类,提供简单的sqlite数据库操作接口,完成数据的基础增删改查操作。
    1. 创建/打开数据库文件
    2. 针对打开的数据库执行操作
        1. 表的操作
        2. 数据的操作
    3. 关闭数据库
*/
#include <iostream>
#include <string>
#include <vector>
#include <sqlite3.h>

class SqliteHelper
{
public:
    typedef int (*SqliteCallback)(void *, int, char **, char **);

    SqliteHelper(const std::string &dbfile) : _dbfile(dbfile), _handler(nullptr) {}

    bool open(int safe_level = SQLITE_OPEN_FULLMUTEX)
    {
        // int sqlite3_open_v2(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs );
        int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_level, nullptr);
        if (ret != SQLITE_OK)
        {
            std::cout << "创建/打开sqlite数据库失败: ";
            std::cout << sqlite3_errmsg(_handler) << std::endl;
            return false;
        }
        return true;
    }
    bool exec(const std::string &sql, SqliteCallback cb, void *arg)
    {
        // int sqlite3_exec(sqlite3*, char *sql, int (*callback)(void*,int,char**,char**), void* arg, char **err)
        int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
        if (ret != SQLITE_OK)
        {
            std::cout << sql << std::endl;
            std::cout << "执行语句失败: ";
            std::cout << sqlite3_errmsg(_handler) << std::endl;
            return false;
        }
        return true;
    }

    void close()
    {
        // int sqlite3_close_v2(sqlite3*);
        if (_handler)
            sqlite3_close_v2(_handler);
    }

private:
    std::string _dbfile;
    sqlite3 *_handler;
};

主要方法详解

  1. 数据库连接管理
  • open方法 :使用sqlite3_open_v2函数打开或创建数据库。该方法允许通过safe_level参数(如SQLITE_OPEN_FULLMUTEX)设置线程安全级别 ,这对于多线程应用至关重要。它组合了SQLITE_OPEN_READWRITE(读写)和SQLITE_OPEN_CREATE(不存在则创建)标志,是常用的打开模式。
  • close方法 :调用sqlite3_close_v2函数清理数据库连接资源。_v2版本是推荐使用的关闭方法。
  1. SQL语句执行
  • exec方法 :这是最核心的方法,封装了sqlite3_exec函数。它可以执行任何SQL语句,包括数据定义语言(DDL)如CREATE TABLE,以及数据操作语言(DML)如INSERT, UPDATE, DELETE, SELECT等。
    • 该方法支持传入一个回调函数 SqliteCallback,这对于处理SELECT查询返回的结果集非常有用。你可以在回调函数中逐行处理查询结果。
    • 参数 arg可用于向回调函数传递用户自定义数据。

注意:有些功能如事务控制等我们没有实现,因为我们在后续的项目中使用不到,所以这里不过多介绍

测试程序:

cpp 复制代码
#include "sqlite.hpp"
#include <cassert>

int select_stu_callback(void *arg, int col_count, char **result, char **fields_name)
{
    std::vector<std::string> *arry = (std::vector<std::string> *)arg;
    arry->push_back(result[0]);
    return 0; // 必须有!!!
}
int main()
{
    SqliteHelper helper("./test.db");
    // 1. 创建/打开库文件
    assert(helper.open());
    // 2. 创建表(不存在则创建), 学生信息: 学号,姓名,年龄
    const char *ct = "create table if not exists student(sn int primary key, name varchar(32), age int);";
    assert(helper.exec(ct, nullptr, nullptr));
    // 3. 新增数据 , 修改, 删除, 查询
    // const char *insert_sql = "insert into student values(1, '小明', 18), (2, '小黑', 19), (3, '小红', 18);";
    // assert(helper.exec(insert_sql, nullptr, nullptr));
    // const char *update_sql = "update student set name='张小明' where sn=1";
    // assert(helper.exec(update_sql, nullptr, nullptr));
    // const char *delete_sql = "delete from student where sn=3";
    // assert(helper.exec(delete_sql, nullptr, nullptr));

    const char *select_sql = "select name from student;";
    std::vector<std::string> arry;
    assert(helper.exec(select_sql, select_stu_callback, &arry));
    for (auto &name : arry)
    {
        std::cout << name << std::endl;
    }
    // 4. 关闭数据库
    helper.close();
    return 0;
}
相关推荐
杨浦老苏2 小时前
将Waline从LeanCloud迁移到MongoDB
数据库·博客·blog·waline
normanhere2 小时前
华为交换机堆叠问题总结
服务器·数据库·华为
程序媛_文乐2 小时前
【redis超过maxmemory值解决方法】
数据库·redis·缓存
semantist@语校2 小时前
第六十篇|语言学校 Prompt 工程化实践:从字段解释到判断边界的结构设计(以日生日本语学园为例)
大数据·数据库·人工智能·百度·ai·prompt·知识图谱
予枫的编程笔记2 小时前
【Redis核心原理篇1】Redis 持久化:RDB、AOF、混合持久化,该怎么选?
数据库·redis·缓存·持久化·aof·rdb
数据知道2 小时前
PostgreSQL 实战:EXPLAIN 执行计划详解
数据库·postgresql
万象.5 小时前
redis数据结构set和zset的基本指令
数据结构·数据库·redis
全栈测试笔记11 小时前
异步函数与异步生成器
linux·服务器·前端·数据库·python
Lee_SmallNorth11 小时前
变态需求之【角色不同访问数据库的用户不同】
java·开发语言·数据库