整理一篇学习笔记,把看到的一些要点和自己的理解都记下来。
🎬 个人主页:艾莉丝努力练剑
❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常用算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:
文章目录
1.3 并发线程安全要求1.4 模块类职责:DataManager
2 ~> 公共数据结构体定义 common.h
3 ~> DataManager头文件 DataManager.h
4 ~> DataManager源文件 DataManager.cpp
- 4.1 构造函数、析构函数
- 4.2 数据库初始化 initDatabase
- 4.3 通用无结果SQL执行工具 executeSQL
- 4.4 Session会话业务接口实现
- 4.4.1 insertSession 插入会话
- 4.4.2 getSession 根据sessionId获取会话(加载消息)
- 4.4.3 updateSessionTimestamp 更新会话时间戳
- 4.4.4 deleteSession 删除会话(级联删除消息)
- 4.4.5 getAllSessionIds 获取全部会话ID(按更新时间倒序)
- 4.4.6 getAllSessions 获取全部会话元数据,不加载消息
- 4.4.7 getSessionCount 获取会话总数
- 4.5.1 insertMessage 插入消息并更新会话时间
- 4.5.2 getSessionMessages 查询会话全部消息
- 4.5.3 deleteSessionMessages 手动删除会话消息
- 5.1 sqlite3_prepare_v2
- 5.2 sqlite3_step
- 5.3 sqlite3_bind_ 参数绑定
- 5.4 sqlite3_column_ 获取查询结果
- 5.5 SQLite外键约束
- 5.6 线程安全
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)
- 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)
暂无评论