【AI大模型接入SDK】SQLite数据持久化模块整体需求

整理一篇学习笔记,把看到的一些要点和自己的理解都记下来。

🎬 个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常用算法:从基础到进阶》《Python干货分享》

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:

文章目录

1.3 并发线程安全要求1.4 模块类职责:DataManager 2 ~> 公共数据结构体定义 common.h 3 ~> DataManager头文件 DataManager.h 4 ~> DataManager源文件 DataManager.cpp 4.5 Message消息业务接口实现 5 ~> SQLite C API核心原理与易错点 6 ~> 业务联动逻辑:DataManager与会话管理器结合 7 ~> 面试高频考点总结结尾

1 ~> SQLite数据持久化模块整体需求

1.1 业务目标

将AI聊天SDK的会话Session数据、消息Message数据持久化存储到SQLite嵌入式数据库。

1.2 数据库表设计

1.2.1 两张核心数据表

1. sessions会话表:存储会话元数据
2. messages消息表:存储每一条聊天消息

1.2.2 表关联约束

  • 消息表的session_id作为外键引用会话表主键session_id
  • 外键约束开启ON DELETE CASCADE级联删除:删除会话时,该会话下属全部消息自动删除,保障数据一致性。
要注意:SQLite默认关闭外键约束,打开数据库连接后需要执行PRAGMA foreign_keys = ON;开启外键,否则级联删除不会生效,原笔记遗漏该关键点。

1.3 并发线程安全要求

  • 多线程同时访问数据库会引发竞争条件,使用std::mutex互斥锁保护全部数据库读写操作。
  • mutable std::mutex _mutex:mutable修饰允许const成员函数内部修改该互斥锁变量。

1.4 模块类职责:DataManager

  • 管理SQLite数据库连接生命周期
  • 数据库初始化、建表
  • Session会话CRUD操作
  • Message消息CRUD操作
  • 封装通用SQL执行工具函数

2 ~> 公共数据结构体定义 common.h

2.1 Session会话结构体

#pragma once
#include
#include
#include
#include "common.h"

namespace ai_chat_sdk
{
	// 会话信息
	struct Session
	{
	    std::string _sessionId;          //会话唯一ID
	    std::string _modelName;          //会话绑定的大模型名称
	    std::vector _messages;  //会话下全部消息,内存缓存,数据库分表存储
	    std::time_t _createdAt;          //会话创建时间戳
	    std::time_t _updatedAt;          //会话最后更新时间戳

	    explicit Session(const std::string& modelName = "")
	        : _modelName(modelName), _createdAt(0), _updatedAt(0)
	    {}
	};

	// 消息结构体
	struct Message
	{
	    std::string _messageId;   //消息唯一ID
	    std::string _role;        //角色 user / assistant / system
	    std::string _content;     //消息文本内容
	    std::time_t _timestamp;   //消息发送时间戳

	    Message(const std::string& role = "", const std::string& content = "")
	        : _role(role), _content(content), _timestamp(0)
	    {}
	};
}


3 ~> DataManager头文件 DataManager.h

3.1 完整头文件代码

#pragma once
#include
#include
#include
#include
#include
#include "common.h"

namespace ai_chat_sdk
{
class DataManager
{
public:
    /**
     * @brief 构造函数:打开/创建SQLite数据库
     * @param dbName sqlite数据库文件路径
     */
    explicit DataManager(const std::string& dbName);

    /**
     * @brief 析构函数:关闭数据库连接,释放资源
     */
    ~DataManager();

    //================ Session会话相关接口 =================
    // 插入一条新会话记录
    bool insertSession(const Session& session);

    // 根据sessionId获取会话元数据,同时加载该会话全部历史消息
    std::shared_ptr getSession(const std::string& sessionId) const;

    // 更新会话最后更新时间戳
    bool updateSessionTimestamp(const std::string& sessionId, std::time_t timestamp);

    // 删除会话,级联删除会话下所有消息
    bool deleteSession(const std::string& sessionId);

    // 获取全部会话ID列表,按更新时间倒序
    std::vector getAllSessionIds() const;

    // 获取全部会话元数据(不预加载消息,按需查询)
    std::vector getAllSessions() const;

    // 获取会话总数量
    size_t getSessionCount() const;

    // ================ Message消息相关接口 =================
    /**
     * @brief 插入一条消息记录,同时更新所属会话的update_time时间戳
     * @param sessionId 归属会话ID
     * @param message 待插入消息对象
     */
    bool insertMessage(const std::string& sessionId, const Message& message);

    // 查询指定会话下全部历史消息
    std::vector getSessionMessages(const std::string& sessionId) const;

    // 手动删除指定会话全部消息(外键级联删除一般不需要调用)
    bool deleteSessionMessages(const std::string& sessionId);

private:
    // 初始化数据库,创建sessions、messages两张数据表
    bool initDatabase();

    /**
     * @brief 执行不需要返回结果集的SQL语句(CREATE、INSERT、UPDATE、DELETE)
     * @param sql sql语句字符串
     * @return 成功返回true,失败false
     */
    bool executeSQL(const std::string& sql);

private:
    sqlite3* _db = nullptr;             //SQLite数据库连接句柄
    std::string _dbName;                //数据库文件名称/路径
    mutable std::mutex _mutex;          //线程安全互斥锁,const成员函数可修改
};
}

3.2 接口业务逻辑要点

1. insertMessage插入消息后务必同步更新对应会话update_time,保证会话列表排序时间正确。
2. getAllSessions批量获取会话时不加载消息列表,避免大量会话时内存爆炸;需要消息再调用getSessionMessages按需加载。
3. getSession单条会话查询时,内部自动调用getSessionMessages填充_messages消息容器。


4 ~> DataManager源文件 DataManager.cpp

4.1 构造函数、析构函数

#include "DataManager.h"
#include "util/myLog.h"
#include

namespace ai_chat_sdk
{
DataManager::DataManager(const std::string& dbName)
    : _dbName(dbName), _db(nullptr)
{
    //打开或者创建sqlite数据库文件
    int rc = sqlite3_open(dbName.c_str(), &_db);
    if (rc != SQLITE_OK)
    {
        ERR("打开数据库失败:{}", sqlite3_errmsg(_db));
        return;
    }
    INFO("打开数据库成功:{}", dbName);

    //【重要】SQLite默认关闭外键约束,必须手动开启,否则ON DELETE CASCADE失效
    executeSQL("PRAGMA foreign_keys = ON;");

    //初始化数据表
    if (!initDatabase())
    {
        sqlite3_close(_db);
        _db = nullptr;
        ERR("初始化数据库表失败");
    }
}

DataManager::~DataManager()
{
    if (_db != nullptr)
    {
        sqlite3_close(_db);
        _db = nullptr;
    }
}

4.2 数据库初始化 initDatabase

bool DataManager::initDatabase()
{
    // 1. 创建会话表 sessions
    std::string createSessionTable = R"(
    CREATE TABLE IF NOT EXISTS sessions(
        session_id TEXT PRIMARY KEY,
        model_name TEXT NOT NULL,
        create_time INTEGER NOT NULL,
        update_time INTEGER NOT NULL
    );
    )";
    if (!executeSQL(createSessionTable))
    {
        return false;
    }

    // 2. 创建消息表 messages,设置外键+级联删除
    std::string createMessageTable = R"(
    CREATE TABLE IF NOT EXISTS messages(
        message_id TEXT PRIMARY KEY,
        session_id TEXT NOT NULL,
        role TEXT NOT NULL,
        content TEXT NOT NULL,
        timestamp INTEGER NOT NULL,
        FOREIGN KEY(session_id) REFERENCES sessions(session_id) ON DELETE CASCADE
    );
    )";
    if (!executeSQL(createMessageTable))
    {
        return false;
    }
    return true;
}

4.3 通用无结果SQL执行工具 executeSQL

用于执行CREATE / INSERT / UPDATE / DELETE,不返回查询结果集

bool DataManager::executeSQL(const std::string& sql)
{
    if (_db == nullptr)
    {
        ERR("数据库未初始化");
        return false;
    }
    char* errMsg = nullptr;
    int rc = sqlite3_exec(_db, sql.c_str(), nullptr, nullptr, &errMsg);
    if (rc != SQLITE_OK)
    {
        ERR("执行SQL失败:{}", errMsg);
        sqlite3_free(errMsg); //sqlite分配的错误内存,必须使用sqlite_free释放
        return false;
    }

    return true;
}

4.4 Session会话业务接口实现

4.4.1 insertSession 插入会话

bool DataManager::insertSession(const Session& session)
{
    std::lock_guard lock(_mutex);

    std::string insertSQL = R"(
    INSERT INTO sessions(session_id, model_name, create_time, update_time)
    VALUES (?, ?, ?, ?);
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, insertSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("insertSession 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return false;
    }

    //绑定参数,time_t转int64_t存入sqlite INTEGER字段
    sqlite3_bind_text(stmt, 1, session._sessionId.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_text(stmt, 2, session._modelName.c_str(), -1, SQLITE_TRANSIENT);
    sqlite3_bind_int64(stmt, 3, static_cast(session._createdAt));
    sqlite3_bind_int64(stmt, 4, static_cast(session._updatedAt));

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE)
    {
        ERR("insertSession 执行SQL失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    INFO("insertSession 插入会话成功 sessionId={}", session._sessionId);

    return true;
}

4.4.2 getSession 根据sessionId获取会话(加载消息)

std::shared_ptr DataManager::getSession(const std::string& sessionId) const
{
    std::lock_guard lock(_mutex);

    std::string selectSQL = R"(
    SELECT model_name, create_time, update_time FROM sessions WHERE session_id = ?;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, selectSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("getSession 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return nullptr;
    }

    sqlite3_bind_text(stmt, 1, sessionId.c_str(), -1, SQLITE_TRANSIENT);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_ROW)
    {
        ERR("getSession 未查询到会话 sessionId={}", sessionId);
        sqlite3_finalize(stmt);
        return nullptr;
    }

    //解析查询行数据
    std::string modelName = reinterpret_cast(sqlite3_column_text(stmt, 0));
    int64_t createTime = sqlite3_column_int64(stmt, 1);
    int64_t updateTime = sqlite3_column_int64(stmt, 2);

    auto session = std::make_shared(modelName);
    session->_sessionId = sessionId;
    session->_createdAt = static_cast(createTime);
    session->_updatedAt = static_cast(updateTime);

    sqlite3_finalize(stmt);

    //加载该会话全部历史消息
    session->_messages = getSessionMessages(sessionId);
    INFO("getSession 获取会话成功 sessionId={}", sessionId);
    return session;
}

4.4.3 updateSessionTimestamp 更新会话时间戳

bool DataManager::updateSessionTimestamp(const std::string& sessionId, std::time_t timestamp)
{
    std::lock_guard lock(_mutex);

    std::string updateSQL = R"(
    UPDATE sessions SET update_time = ? WHERE session_id = ?;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, updateSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("updateSessionTimestamp 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return false;
    }

    sqlite3_bind_int64(stmt, 1, static_cast(timestamp));
    sqlite3_bind_text(stmt, 2, sessionId.c_str(), -1, SQLITE_TRANSIENT);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE)
    {
        ERR("updateSessionTimestamp 执行SQL失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    INFO("updateSessionTimestamp 更新会话时间戳成功 sessionId={}", sessionId);

    return true;
}

4.4.4 deleteSession 删除会话(级联删除消息)

bool DataManager::deleteSession(const std::string& sessionId)
{
    std::lock_guard lock(_mutex);

    std::string deleteSQL = R"(
    DELETE FROM sessions WHERE session_id = ?;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, deleteSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("deleteSession 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, sessionId.c_str(), -1, SQLITE_TRANSIENT);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE)
    {
        ERR("deleteSession 执行SQL失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    INFO("deleteSession 删除会话成功 sessionId={}", sessionId);

    return true;
}

4.4.5 getAllSessionIds 获取全部会话ID(按更新时间倒序)

std::vector DataManager::getAllSessionIds() const
{
    std::lock_guard lock(_mutex);
    std::vector result;

    std::string selectSQL = R"(
    SELECT session_id FROM sessions ORDER BY update_time DESC;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, selectSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("getAllSessionIds 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return {};
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
    {
        std::string sid = reinterpret_cast(sqlite3_column_text(stmt, 0));
        result.push_back(sid);
    }

    if (rc != SQLITE_DONE)
    {
        ERR("getAllSessionIds 查询执行异常:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return {};
    }

    sqlite3_finalize(stmt);
    INFO("getAllSessionIds 获取会话ID列表成功,数量={}", result.size());

    return result;
}

4.4.6 getAllSessions 获取全部会话元数据,不加载消息

std::vector DataManager::getAllSessions() const
{
    std::lock_guard lock(_mutex);
    std::vector result;

    std::string selectSQL = R"(
    SELECT session_id, model_name, create_time, update_time
    FROM sessions
    ORDER BY update_time DESC;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, selectSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("getAllSessions 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return {};
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
    {
        std::string sid = reinterpret_cast(sqlite3_column_text(stmt, 0));
        std::string modelName = reinterpret_cast(sqlite3_column_text(stmt, 1));
        int64_t createTime = sqlite3_column_int64(stmt, 2);
        int64_t updateTime = sqlite3_column_int64(stmt, 3);

        auto sess = std::make_shared(modelName);
        sess->_sessionId = sid;
        sess->_createdAt = static_cast(createTime);
        sess->_updatedAt = static_cast(updateTime);
        //此处不加载_messages消息,按需查询
        result.push_back(sess);
    }

    if (rc != SQLITE_DONE)
    {
        ERR("getAllSessions 查询执行异常:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return {};
    }

    sqlite3_finalize(stmt);
    INFO("getAllSessions 获取全部会话元数据成功,数量={}", result.size());

    return result;
}

4.4.7 getSessionCount 获取会话总数

size_t DataManager::getSessionCount() const
{
    std::lock_guard lock(_mutex);

    std::string selectSQL = R"(
    SELECT COUNT(*) FROM sessions;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, selectSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("getSessionCount 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return 0;
    }

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_ROW)
    {
        ERR("getSessionCount 查询执行异常:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return 0;
    }

    size_t count = static_cast(sqlite3_column_int64(stmt, 0));
    sqlite3_finalize(stmt);
    INFO("getSessionCount 获取会话总数={}", count);

    return count;
}

4.5 Message消息业务接口实现

4.5.1 insertMessage 插入消息并更新会话时间

bool DataManager::insertMessage(const std::string& sessionId, const Message& message)
{
    std::lock_guard lock(_mutex);

    //1.插入消息记录
    std::string insertMsgSQL = R"(
    INSERT INTO messages(message_id, session_id, role, content, timestamp)
    VALUES (?, ?, ?, ?, ?);
    )";

    sqlite3_stmt* insertStmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, insertMsgSQL.c_str(), -1, &insertStmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("insertMessage 插入消息预处理失败:{}", sqlite3_errmsg(_db));
        return false;
    }

    sqlite3_bind_text(insertStmt,1,message._messageId.c_str(),-1,SQLITE_TRANSIENT);
    sqlite3_bind_text(insertStmt,2,sessionId.c_str(),-1,SQLITE_TRANSIENT);
    sqlite3_bind_text(insertStmt,3,message._role.c_str(),-1,SQLITE_TRANSIENT);
    sqlite3_bind_text(insertStmt,4,message._content.c_str(),-1,SQLITE_TRANSIENT);
    sqlite3_bind_int64(insertStmt,5,static_cast(message._timestamp));

    rc = sqlite3_step(insertStmt);
    if (rc != SQLITE_DONE)
    {
        ERR("insertMessage 插入消息执行失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(insertStmt);
        return false;
    }

    //2.同步更新会话update_time为消息的时间戳
    std::string updateSessionSQL = R"(
    UPDATE sessions SET update_time = ? WHERE session_id = ?;
    )";

    sqlite3_stmt* updateStmt = nullptr;
    rc = sqlite3_prepare_v2(_db, updateSessionSQL.c_str(), -1, &updateStmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("insertMessage 更新会话时间预处理失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(insertStmt);
        return false;
    }

    sqlite3_bind_int64(updateStmt,1,static_cast(message._timestamp));
    sqlite3_bind_text(updateStmt,2,sessionId.c_str(),-1,SQLITE_TRANSIENT);

    rc = sqlite3_step(updateStmt);
    if (rc != SQLITE_DONE)
    {
        ERR("insertMessage 更新会话时间执行失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(insertStmt);
        sqlite3_finalize(updateStmt);
        return false;
    }

    sqlite3_finalize(insertStmt);
    sqlite3_finalize(updateStmt);
    INFO("insertMessage 插入消息成功 messageId={}", message._messageId);

    return true;
}

4.5.2 getSessionMessages 查询会话全部消息

std::vector DataManager::getSessionMessages(const std::string& sessionId) const
{
    std::lock_guard lock(_mutex);
    std::vector result;

    std::string selectSQL = R"(
    SELECT message_id, role, content, timestamp
    FROM messages
    WHERE session_id = ?;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, selectSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("getSessionMessages 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return {};
    }

    sqlite3_bind_text(stmt, 1, sessionId.c_str(), -1, SQLITE_TRANSIENT);

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW)
    {
        Message msg;
        msg._messageId = reinterpret_cast(sqlite3_column_text(stmt,0));
        msg._role = reinterpret_cast(sqlite3_column_text(stmt,1));
        msg._content = reinterpret_cast(sqlite3_column_text(stmt,2));
        msg._timestamp = static_cast(sqlite3_column_int64(stmt,3));
        result.push_back(msg);
    }

    if (rc != SQLITE_DONE)
    {
        ERR("getSessionMessages 查询异常:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return {};
    }

    sqlite3_finalize(stmt);
    INFO("getSessionMessages 获取会话消息成功 sessionId={},消息数量={}", sessionId, result.size());

    return result;
}

4.5.3 deleteSessionMessages 手动删除会话消息

业务优先使用会话删除的外键级联删除,此接口为备用接口

bool DataManager::deleteSessionMessages(const std::string& sessionId)
{
    std::lock_guard lock(_mutex);

    std::string deleteSQL = R"(
    DELETE FROM messages WHERE session_id = ?;
    )";

    sqlite3_stmt* stmt = nullptr;
    int rc = sqlite3_prepare_v2(_db, deleteSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK)
    {
        ERR("deleteSessionMessages 预处理SQL失败:{}", sqlite3_errmsg(_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, sessionId.c_str(), -1, SQLITE_TRANSIENT);
    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE)
    {
        ERR("deleteSessionMessages 执行SQL失败:{}", sqlite3_errmsg(_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    INFO("deleteSessionMessages 删除会话全部消息成功 sessionId={}", sessionId);

    return true;
}
} //namespace ai_chat_sdk


5 ~> SQLite C API核心原理与易错点

5.1 sqlite3_prepare_v2

  • 作用:将SQL文本编译预处理为sqlite3_stmt语句对象,支持参数占位符?
  • 返回值SQLITE_OK代表预处理成功。
  • 用完stmt务必调用sqlite3_finalize释放,否则内存泄漏。

5.2 sqlite3_step

返回宏含义SQLITE_ROW查询语句:获取到一行有效结果数据SQLITE_DONE执行完成,没有更多数据;INSERT/UPDATE/DELETE正常完成返回此值

5.3 sqlite3_bind_ 参数绑定

  • sqlite3_bind_text(stmt, index, str, len, destructor)
index占位符下标从1开始,不是0
  • len传-1自动读取c字符串\0截止
  • SQLITE_TRANSIENT:告诉sqlite内部复制一份字符串副本,外部字符串销毁也安全。
sqlite3_bind_int64:C++std::time_t务必强转为int64_t存入SQLite INTEGER字段。

5.4 sqlite3_column_ 获取查询结果

  • 列下标从0开始,与bind下标不一样,高频踩坑点。
  • sqlite3_column_text返回const unsigned char*,必须reinterpret_cast转为C++字符串。

5.5 SQLite外键约束

  • SQLite默认关闭外键约束,打开数据库连接必须执行PRAGMA foreign_keys = ON;,否则ON DELETE CASCADE级联删除完全失效,原笔记缺失该关键点。
  • 外键约束生效条件:数据库不是内存数据库、WAL/DELETE日志模式、开关PRAGMA打开。

5.6 线程安全

  • SQLite三种线程模式:Single‑Thread / Multi‑Thread / Serialized。
  • 本工程采用Serialized串行模式,应用层额外加std::mutex做二次防护,保证多线程读写安全。
  • mutable std::mutex:const成员函数内部也可以对锁进行加锁解锁操作。

6 ~> 业务联动逻辑:DataManager与会话管理器结合

6.1 会话管理器SessionManager职责

1. 在内存中管理活跃会话;
2. 会话创建、销毁时调用DataManager持久化写入数据库;
3. 程序启动时调用DataManager加载历史会话列表;
4. 每次发送/接收AI消息,调用insertMessage写入消息,接口内部自动更新会话时间戳。

6.2 数据流转流程

1. 新建会话:内存生成Session对象 → DataManager::insertSession()写入sessions表。
2. 发送/收到消息:内存生成Message对象 → DataManager::insertMessage(sessionId, msg)写入messages表,自动更新会话update_time。
3. 打开历史会话:传入sessionId调用getSession(sessionId),加载会话元数据+全部历史消息到内存Session对象。
4. 删除会话:调用deleteSession(sessionId),数据库依靠外键ON DELETE CASCADE自动删除该会话所有消息。
5. 程序启动:调用getAllSessionIds()获取全部会话ID,按需加载会话元数据。


7 ~> 面试高频考点总结

1. 为什么会话和消息分两张表存储?
一对多关系:一个Session对应多条Message;
2. 减少冗余,会话元数据只存储一份;
3. 利用外键级联删除保证数据一致性。

为什么插入消息的时候,必须更新会话update_time?

1. 会话列表按照update_time倒序展示,最新聊天会话排在最上方;新增消息代表会话发生变更,需要刷新会话时间戳。

SQLite stmt对象为什么必须sqlite3_finalize?

1. stmt对象是sqlite内部堆内存分配,不释放会造成内存泄漏,长期运行程序内存持续上涨。

SQLITE_TRANSIENT的作用是什么?

1. 告诉SQLite需要复制一份字符串副本;当外部传入的字符串生命周期完成销毁,SQLite内部仍然持有有效拷贝,防止野指针。

为什么要用mutable修饰mutex成员变量?

1. const成员函数不允许修改类成员变量;互斥锁加锁解锁需要修改锁内部状态,mutable允许const函数修改该成员。

SQLite外键级联删除不生效排查点

1. 是否执行PRAGMA foreign_keys = ON打开开关;
2. 确认建表语句FOREIGN KEY + ON DELETE CASCADE语法正确;
3. 确认不是内存数据库。


结尾

uu们,本文的内容到这里就全部完成了,艾莉丝在这里再次

艾莉丝努力练剑

C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主


👀 【关注】 跟随我一起深耕技术领域,见证每一次成长。

❤️
【点赞】 让优质内容被更多人看见,让知识传递更有力量。

⭐
【收藏】 把核心知识点存好,在需要时随时查、随时用。

💬
【评论】 分享你的经验或疑问,评论区一起交流避坑!

不要忘记给博主“一键四连”哦!

“今日练剑达成!”

“技术之路难免有困惑,但同行的人会让前进更有方向。”

结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

往期回顾:

【AI大模型接入SDK】SQLite C API编程实战:学生表CRUD案例

🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡
>
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

今天的内容大概就这些,实际开发中大家还会遇到更多细节,欢迎留言分享自己的经验。

评论 (0)

暂无评论