IndexedDB不支持原生复合主键,但可通过数组或对象作为structured key模拟;推荐使用单一主键配合复合索引实现多条件查询,更灵活健壮。

复合主键在 IndexedDB 中并不存在原生支持
IndexedDB 本身不支持传统数据库意义上的“复合主键”(如 MySQL 中的 (user_id, order_date))。它的主键只能是单个值,但可以通过结构化键(structured key)模拟复合主键行为——即使用数组或对象作为主键值,前提是该键被显式指定为 keyPath 或通过 key generator 生成时能稳定推导。
用 keyPath 实现“类复合主键”的表结构设计
当你希望按多个字段共同唯一标识一条记录(例如:用户ID + 时间戳),可将这两个字段组合成一个数组作为主键,并将其定义为 keyPath:
- 在
createObjectStore时传入{ keyPath: ['userId', 'timestamp'] } - 写入数据时,必须确保对象包含这两个字段,且值不可为
undefined或null - 示例数据结构:
{ userId: 123, timestamp: 1715823400000, content: "hello" } - 查询时可用
store.get([123, 1715823400000])精确匹配
用 key generator 配合 structured key 的注意事项
IndexedDB 的 autoIncrement 不支持数组或对象主键,所以不能对 structured key 启用自增。若需“自动生成复合键”,必须手动构造:
- 禁用
autoIncrement,显式设置keyPath - 插入前拼接主键:比如用
[userId, Date.now()]保证时间维度唯一性 - 注意时钟回拨或并发写入可能导致重复键,建议加毫秒级随机后缀或使用
crypto.randomUUID()辅助去重
索引比主键更适合多条件查询场景
如果目标是高效查询(如“查某用户所有订单”或“查某时间段内所有记录”),更推荐主键保持简单(如 ID)+ 多建 index:
立即学习“Java免费学习笔记(深入)”;
- 主键设为
id(数字或字符串),便于增删改 - 创建复合索引:
store.createIndex('by_user_time', ['userId', 'timestamp'], { unique: false }) - 查询时用
index.getAll(IDBKeyRange.bound([123, 0], [123, Date.now()]))范围检索 - 索引支持部分匹配(如只传
[123]查该用户全部记录)
小结:优先选索引,慎用 structured keyPath
structured keyPath 虽能模拟复合主键,但牺牲了灵活性(无法 autoIncrement、更新主键需删除重建、序列化/比较开销略高)。实际开发中,90% 的场景用单一主键 + 复合索引更健壮、易维护。只有在极少数需要强唯一约束且写入路径完全可控时,才考虑数组 keyPath。


















