add只新增、主键存在时抛ConstraintError回滚;put则插入或覆盖,主键存在即替换整条记录,无合并逻辑。

IndexedDB 中主键冲突不是“报错就完事”,而是由你主动选择行为:用 add 拒绝重复,用 put 自动覆盖或插入——关键在语义,不在报错本身。
add 和 put 的行为差异是核心
两者都向 ObjectStore 写入数据,但对已有主键的反应完全不同:
-
add 方法:只做“纯新增”。如果主键已存在,直接抛出
ConstraintError,事务回滚,不修改任何数据。 - put 方法:做“插入或替换”。主键不存在时新增;存在时直接覆盖整条记录(旧值被丢弃,无合并逻辑)。
注意:两者都要求主键合法(非 undefined、null 或重复生成)。若使用自动生成主键(如 keyPath + autoIncrement),add 和 put 行为一致(都生成新主键),此时不会触发冲突。
如何避免意外覆盖?加版本号或时间戳字段
单纯依赖 put 容易丢失更新(后写覆盖先写)。真实业务中建议引入乐观并发控制:
- 在每条记录中存一个
version字段(数字递增)或updatedAt时间戳; - 写入前读取当前记录,比对版本;
- 仅当本地版本 ≥ 服务端版本时才调用
put,否则提示用户“数据已被他人修改”; - 成功写入后,
put不返回旧值,所以需在事务中显式get原记录做校验。
批量写入时的冲突处理策略
一次写入多条记录时,无法靠单个 put 实现“部分成功”。可行做法:
- 拆成多个独立事务,每个事务只操作一条记录,并分别监听
onsuccess和onerror; - 对失败项分类:若是
ConstraintError,可改用put重试(表示你想覆盖); - 若想跳过冲突项继续执行,捕获错误后
event.preventDefault()并记录日志,不中断整个流程。
主键设计本身能减少冲突概率
前端场景下,避免依赖服务端分配 ID,推荐组合式主键:
- 用
userId + timestamp + randomSuffix拼接字符串,保证离线生成也几乎不重复; - 避免纯数字自增主键(多个设备同时新增易撞);
- 若必须用数字主键,搭配
autoIncrement: true和keyPath,让 IndexedDB 自动管理,彻底规避手动冲突。

















