DeepChat本地存储方案:better-sqlite3与数据持久化实践
2026-02-05 05:52:17作者:曹令琨Iris
方案背景与技术选型
DeepChat作为连接AI与个人数据的智能助手,采用better-sqlite3作为本地存储解决方案,通过src/main/presenter/sqlitePresenter/index.ts实现数据持久化。该方案基于SQLCipher加密扩展,提供事务支持、数据迁移和损坏恢复机制,确保用户对话历史、消息内容等核心数据的安全存储。
技术栈组成
- 核心库:better-sqlite3-multiple-ciphers(SQLCipher扩展版)
- 数据模型:Conversations/Messages/Attachments三表结构
- 安全特性:数据库文件加密、WAL模式、自动备份
- 维护机制:版本迁移、损坏恢复、事务支持
数据库架构设计
核心表结构
DeepChat采用模块化表设计,各表职责明确且通过外键关联:
erDiagram
CONVERSATIONS ||--o{ MESSAGES : contains
MESSAGES ||--o{ MESSAGE_ATTACHMENTS : has
ATTACHMENTS }|--|| MESSAGE_ATTACHMENTS : references
- Conversations表:存储对话元数据(标题、创建时间、设置)
- Messages表:存储消息内容(文本、角色、状态、序号)
- Attachments表:存储文件附件元数据
- MessageAttachments表:消息与附件的多对多关联
初始化流程
数据库连接建立过程包含错误处理与自动恢复机制,关键步骤如下:
// 核心初始化逻辑 [src/main/presenter/sqlitePresenter/index.ts#L32-L92]
constructor(dbPath: string, password?: string) {
this.dbPath = dbPath
try {
// 确保目录存在
const dbDir = path.dirname(dbPath)
if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true })
// 初始化加密连接
this.db = new Database(dbPath)
this.db.pragma('journal_mode = WAL')
if (password) {
this.db.pragma(`cipher='sqlcipher'`)
this.db.pragma(`key='${password}'`)
}
// 表初始化与迁移
this.initTables()
this.initVersionTable()
this.migrate()
} catch (error) {
// 损坏恢复流程
this.backupDatabase()
this.cleanupDatabaseFiles()
// 重建数据库
this.db = new Database(dbPath)
// ...重新初始化
}
}
安全存储实现
加密机制
采用SQLCipher实现数据库透明加密,加密密钥通过配置系统安全管理:
// 加密配置 [src/main/presenter/sqlitePresenter/index.ts#L45-L48]
if (password) {
this.db.pragma(`cipher='sqlcipher'`)
this.db.pragma(`key='${password}'`)
}
数据备份策略
数据库损坏时自动创建时间戳备份,并清理损坏文件:
// 备份逻辑 [src/main/presenter/sqlitePresenter/index.ts#L98-L110]
private backupDatabase(): void {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const backupPath = `${this.dbPath}.${timestamp}.bak`
if (fs.existsSync(this.dbPath)) {
fs.copyFileSync(this.dbPath, backupPath)
console.log(`Database backed up to: ${backupPath}`)
}
}
数据操作接口
核心CRUD实现
SQLitePresenter封装了完整的数据操作API,以下为常用操作示例:
创建对话
// [src/main/presenter/sqlitePresenter/index.ts#L215-L220]
public async createConversation(
title: string,
settings: Partial<CONVERSATION_SETTINGS> = {}
): Promise<string> {
return this.conversationsTable.create(title, settings)
}
插入消息
// [src/main/presenter/sqlitePresenter/index.ts#L254-L278]
public async insertMessage(
conversationId: string,
content: string,
role: string,
parentId: string,
metadata: string = '{}',
orderSeq: number = 0,
tokenCount: number = 0,
status: string = 'pending',
isContextEdge: number = 0,
isVariant: number = 0
): Promise<string> {
return this.messagesTable.insert(/* 参数 */)
}
事务支持
通过better-sqlite3的事务API确保多操作原子性:
// [src/main/presenter/sqlitePresenter/index.ts#L330-L332]
public async runTransaction(operations: () => void): Promise<void> {
await this.db.transaction(operations)()
}
版本迁移与维护
增量迁移机制
系统通过版本表追踪 schema 变更,支持多表协同迁移:
// [src/main/presenter/sqlitePresenter/index.ts#L160-L207]
private migrate() {
const migrations = new Map<number, string[]>()
// 收集各表迁移脚本
tables.forEach((table) => {
for (let version = this.currentVersion + 1; version <= latestVersion; version++) {
const sql = table.getMigrationSQL?.(version)
if (sql) {
migrations.set(version, [...migrations.get(version) || [], sql])
}
}
})
// 按版本顺序执行迁移
const versions = Array.from(migrations.keys()).sort((a, b) => a - b)
for (const version of versions) {
this.db.transaction(() => {
migrationSQLs.forEach(sql => this.db.exec(sql))
this.db.prepare('INSERT INTO schema_versions VALUES (?, ?)')
.run(version, Date.now())
})()
}
}
表版本管理
每个表独立维护版本信息,通过getLatestVersion和getMigrationSQL接口提供迁移脚本:
// 版本管理示例 [src/main/presenter/sqlitePresenter/index.ts#L171-L174]
const latestVersion = tables.reduce((maxVersion, table) => {
const tableMaxVersion = table.getLatestVersion?.() || 0
return Math.max(maxVersion, tableMaxVersion)
}, 0)
性能优化策略
WAL模式
默认启用Write-Ahead Logging模式提升并发性能:
// [src/main/presenter/sqlitePresenter/index.ts#L43]
this.db.pragma('journal_mode = WAL')
WAL模式优势:
- 读操作不阻塞写操作
- 写操作只阻塞其他写操作
- 更小的I/O开销
索引设计
各表通过合理索引优化查询性能,例如Messages表的复合索引:
-- 示例索引设计(推测)
CREATE INDEX idx_messages_conversation_order ON messages(conversation_id, order_seq);
CREATE INDEX idx_messages_parent ON messages(parent_id);
实际应用场景
典型数据流向
以用户发送消息为例,完整数据存储流程:
sequenceDiagram
participant U as User
participant V as ViewModel
participant P as SQLitePresenter
participant M as MessagesTable
U->>V: 发送消息
V->>P: createConversation(标题)
P->>P: 生成conversation_id
V->>P: insertMessage(conversation_id, 内容, "user")
P->>M: insert(消息数据)
M-->>P: 返回message_id
P-->>V: 存储成功
数据恢复案例
当数据库文件损坏时,系统自动执行恢复流程:
1. 创建备份文件(如chat.db.2025-10-23T02-26-17.bak)
2. 删除损坏文件及WAL/SHM文件
3. 重建空数据库并初始化表结构
4. 记录错误日志便于问题排查
扩展与最佳实践
自定义SQL操作
如需执行复杂查询,可通过底层连接直接操作:
// 扩展示例
const customQuery = (conversationId: string) => {
return this.db.prepare(`
SELECT m.* FROM messages m
JOIN conversations c ON m.conversation_id = c.id
WHERE c.id = ? AND m.status = 'completed'
ORDER BY m.order_seq DESC LIMIT 1
`).get(conversationId)
}
备份策略建议
- 定期完整备份(如每日)
- 关键操作前触发增量备份
- 备份文件加密存储
- 定期测试恢复流程
总结
DeepChat的SQLite存储方案通过模块化设计、安全加密和性能优化,为AI助手提供了可靠的数据持久化基础。核心优势包括:
- 安全性:全程加密保护用户隐私数据
- 可靠性:完善的错误处理与自动恢复机制
- 扩展性:版本化迁移支持持续功能迭代
- 性能:WAL模式与索引优化保障操作流畅
完整实现代码参见src/main/presenter/sqlitePresenter/目录,包含表定义、迁移脚本和核心业务逻辑。
登录后查看全文
热门项目推荐
相关项目推荐
Kimi-K2.5Kimi K2.5 是一款开源的原生多模态智能体模型,它在 Kimi-K2-Base 的基础上,通过对约 15 万亿混合视觉和文本 tokens 进行持续预训练构建而成。该模型将视觉与语言理解、高级智能体能力、即时模式与思考模式,以及对话式与智能体范式无缝融合。Python00- QQwen3-Coder-Next2026年2月4日,正式发布的Qwen3-Coder-Next,一款专为编码智能体和本地开发场景设计的开源语言模型。Python00
xw-cli实现国产算力大模型零门槛部署,一键跑通 Qwen、GLM-4.7、Minimax-2.1、DeepSeek-OCR 等模型Go06
PaddleOCR-VL-1.5PaddleOCR-VL-1.5 是 PaddleOCR-VL 的新一代进阶模型,在 OmniDocBench v1.5 上实现了 94.5% 的全新 state-of-the-art 准确率。 为了严格评估模型在真实物理畸变下的鲁棒性——包括扫描伪影、倾斜、扭曲、屏幕拍摄和光照变化——我们提出了 Real5-OmniDocBench 基准测试集。实验结果表明,该增强模型在新构建的基准测试集上达到了 SOTA 性能。此外,我们通过整合印章识别和文本检测识别(text spotting)任务扩展了模型的能力,同时保持 0.9B 的超紧凑 VLM 规模,具备高效率特性。Python00
KuiklyUI基于KMP技术的高性能、全平台开发框架,具备统一代码库、极致易用性和动态灵活性。 Provide a high-performance, full-platform development framework with unified codebase, ultimate ease of use, and dynamic flexibility. 注意:本仓库为Github仓库镜像,PR或Issue请移步至Github发起,感谢支持!Kotlin08
VLOOKVLOOK™ 是优雅好用的 Typora/Markdown 主题包和增强插件。 VLOOK™ is an elegant and practical THEME PACKAGE × ENHANCEMENT PLUGIN for Typora/Markdown.Less00
项目优选
收起
deepin linux kernel
C
27
11
OpenHarmony documentation | OpenHarmony开发者文档
Dockerfile
532
3.75 K
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
336
178
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
886
596
Ascend Extension for PyTorch
Python
340
405
暂无简介
Dart
772
191
Nop Platform 2.0是基于可逆计算理论实现的采用面向语言编程范式的新一代低代码开发平台,包含基于全新原理从零开始研发的GraphQL引擎、ORM引擎、工作流引擎、报表引擎、规则引擎、批处理引引擎等完整设计。nop-entropy是它的后端部分,采用java语言实现,可选择集成Spring框架或者Quarkus框架。中小企业可以免费商用
Java
12
1
openJiuwen agent-studio提供零码、低码可视化开发和工作流编排,模型、知识库、插件等各资源管理能力
TSX
986
247
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
416
4.21 K
React Native鸿蒙化仓库
JavaScript
303
355