add和put的核心区别在于主键冲突处理:add在主键已存在时抛constrainterror,拒绝覆盖;put则无论主键是否存在均成功,已存在即更新、不存在即新增。

add 和 put 的核心区别在哪
关键看是否允许覆盖:用 add() 往已存在主键的记录上写,会直接报错 ConstraintError;而 put() 无论主键是否存在,都成功写入——不存在就新增,存在就覆盖。别指望它们自动“智能判断”,行为完全由方法名决定。
必须先打开数据库并创建对象仓库
没建好仓库就调 add() 或 put(),会立刻抛 InvalidStateError。注意两点:
-
indexedDB.open()返回的request对象,在upgradeneeded事件里才能用db.createObjectStore() - 即使只是读写,首次打开时如果版本号更高,也会触发
upgradeneeded;没监听它,后续事务就拿不到对象仓库引用
示例片段(仅示意流程):
const request = indexedDB.open('mydb', 1);
request.onupgradeneeded = event => {
const db = event.target.result;
if (!db.objectStoreNames.contains('users')) {
db.createObjectStore('users', { keyPath: 'id' });
}
};
add/put 必须在事务中执行,且不能跨事务复用对象仓库
常见错误是把 objectStore 实例缓存起来,下次事务还用它——这会报 TransactionInactiveError。每次操作前都得从当前事务里重新获取:
- 事务生命周期很短,
transaction.objectStore('xxx')返回的对象只对本次事务有效 -
add()和put()是异步方法,返回IDBRequest,要监听onsuccess或onerror拿结果 - 主键字段缺失或类型不符(比如设了
keyPath: 'id'却传入{ name: 'a' }),会触发DataError
正确写法:
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
const req = store.put({ id: 1, name: 'Alice' });
req.onsuccess = () => console.log('saved');
req.onerror = () => console.error(req.error.name); // ConstraintError / DataError 等
主键自增场景下 add 和 put 的行为差异
如果对象仓库用 { autoIncrement: true } 创建(不设 keyPath 或设为 null),主键由 IndexedDB 自动分配:
-
add()总是生成新主键,哪怕你显式传了id字段也不会用 -
put()如果传了主键值(如{ id: 5 }),就用这个值;如果不传,也自动生成新主键 - 此时两者都不会报
ConstraintError,但语义不同:add()表明“坚决不覆盖”,put()仍保留覆盖能力
容易忽略的是:自增主键的值不是连续递增的整数,而是单调递增的数字(可能跳变),别依赖其连续性做业务逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











