IndexedDB 增量更新:实现精准的字段级“补丁”

在 SQL 中,我们可以执行 UPDATE table SET field = 'val' WHERE id = 1。但在 IndexedDB 的世界里,原生 API 只提供了 put()put 的本质是 "全量覆盖" :如果你只传一个字段,整个对象剩下的部分都会丢失。

处理这种"增量更新"时,必须保证原子性(Atomicity) ,尤其是在处理长篇 AI Prompt 时,防止数据在"读取-修改-写入"的过程中被并发操作篡改。


1. 核心原理:Get-Modify-Put 模式

由于 IndexedDB 不支持部分更新,我们必须手动实现一个 patch 方法。关键点在于:获取数据、合并字段、重新存入这三个步骤必须在**同一个事务(Transaction)**中完成。

2. 代码实现:给 PromptDB 增加 patch 方法

我们在之前封装的 PromptDB 基础上,新增一个智能增量更新函数:

JavaScript

javascript 复制代码
/**
 * 增量更新指定 ID 的数据
 * @param {string} id - 主键
 * @param {Object} changes - 需要修改的字段,例如 { title: '新标题' }
 */
async patch(id, changes) {
  await this.init();
  
  return new Promise((resolve, reject) => {
    // 1. 开启读写事务
    const transaction = this.db.transaction(this.storeName, 'readwrite');
    const store = transaction.objectStore(this.storeName);

    // 2. 先读取原始数据
    const getRequest = store.get(id);

    getRequest.onsuccess = () => {
      const data = getRequest.result;
      if (!data) {
        reject(new Error(`ID 为 ${id} 的记录不存在`));
        return;
      }

      // 3. 合并差异 (使用 Object.assign 或 展开运算符)
      const updatedData = { ...data, ...changes, updatedAt: Date.now() };

      // 4. 写回数据库
      const putRequest = store.put(updatedData);
      
      putRequest.onsuccess = () => resolve(updatedData);
      putRequest.onerror = () => reject(new Error('增量更新失败'));
    };

    transaction.onerror = () => reject(new Error('事务异常'));
  });
}

3. 为什么必须在同一个"事务"里?

你肯定关心并发控制

  • 场景 :AI 正在流式更新 content 字段,而用户同时在点击"收藏"按钮(修改 isFavorite 字段)。
  • 风险 :如果 getput 分属不同事务,可能会发生"写覆盖":用户读取了旧数据,修改了收藏状态,此时 AI 更新了内容,用户最后写回时,把 AI 刚更新的内容又覆盖回了旧版。
  • 解决 :IndexedDB 的事务锁机制能确保在 onsuccess 回调完成前,其他写操作必须排队,从而保证了增量操作的原子性

4. 8 个具体的业务实战场景

场景 patch 传参示例 意义
字数统计 { wordCount: 1500 } 仅更新统计信息,不触碰数万字的 Prompt 正文
收藏状态 { isFavorite: true } 极速切换,不影响复杂的上下文关联
流式更新 { content: currentText } 在 AI 打字过程中,频繁同步内容,避免丢失进度
标签修正 { tags: [...oldTags, '金融'] } 增量添加标签索引
错误标记 { lastError: 'API Timeout' } 记录异常状态,保留原始请求参数
读取计数 { views: data.views + 1 } 简单的原子累加
版本回退 { version: 2, content: history[2] } 部分字段回滚到历史版本
UI 状态记录 { isExpanded: false } 记录卡片折叠状态,不触碰业务数据

5. 性能优化:大数据量下的增量更新

如果你处理的是超过 100KB 的大型 Prompt 对象,频繁的 patch 会产生大量的垃圾回收(GC)压力。

  1. 防抖处理 (Debounce) :对于"用户改了一个词"这种高频操作,建议在内存中缓冲 500ms,再调用一次 patch
  2. 字段拆分 :如果某个字段(如 chat_history)会无限增长,建议将其拆分为另一个 Object Store ,通过 ID 关联,而不是塞在一个超大的对象里不断 patch
  3. 使用 Proxy :在前端框架中,可以用 Proxy 监听对象变化,自动收集 changes 补丁包,实现自动化增量备份。

相关推荐
San813_LDD11 小时前
[C语言]《Dev-C++ 报错解决手册(Day0607 精华版)》
java·前端·javascript
xiaofeichaichai17 小时前
Webpack
前端·webpack·node.js
问心无愧051317 小时前
ctf show web入门111
android·前端·笔记
唐某人丶17 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界17 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
JS菌18 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
excel19 小时前
HLS TS 文件损坏的元凶:Git 提交与拉取
前端
Aphasia31119 小时前
https连接传输流程
前端·面试
徐小夕19 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github