indexeddb事务一致性靠自动中止与回滚保障:必须显式创建事务并绑定所有操作,监听transaction.onerror而非单个请求错误,避免跨异步边界使用,且批量操作应合并至单个readwrite事务以确保原子性。

IndexedDB 本身不提供显式的“提交”或“回滚”API,事务的一致性靠自动机制保障:只要操作出错且未被拦截,整个事务就会自动中止并回滚。关键在于正确创建事务、绑定操作、监听错误,并避免常见陷阱。
事务必须显式创建并指定作用域
所有读写操作都必须在事务内进行,不能脱离事务直接调用 add()、put() 等方法。创建时需明确:
- 涉及的对象仓库名称(数组形式),例如
['users', 'orders'] - 访问模式:
'readonly'或'readwrite'('versionchange'仅用于数据库升级)
错误示例:漏传对象仓库名、传入不存在的仓库、在 readonly 事务里调用 add() —— 这些都会立即触发 onerror 并中止事务。
错误未捕获 = 自动回滚
IndexedDB 的回滚是隐式且不可逆的。只要事务中任意请求(如 add() 报 ConstraintError,或 get() 读取失败)抛出未处理的错误,事务就会中止,之前所有变更全部丢弃。
- 务必为事务监听
onerror,而不是只监听单个请求的错误 - 不要在错误回调里调用
event.preventDefault(),否则可能阻止默认回滚行为 - 若需部分容错(如跳过某条非法数据),应在发起请求前校验,而非依赖事务内“吞掉错误”
事务生命周期不可控,禁止跨异步边界使用
事务在事件循环空闲时自动关闭,无法手动延长时间。以下操作会导致事务提前失效或报错:
- 在
setTimeout、Promise.then中继续使用已创建的objectStore - 把事务对象或其
objectStore引用保存到外部变量,之后再调用方法 - 在事务未完成前重新打开数据库或执行其他事务
正确做法:所有操作链必须在同一个同步上下文内完成,或用 async/await 配合 Dexie.js 等封装库管理生命周期。
批量操作尽量合并到单个读写事务
多个独立事务不仅性能差,还可能因执行顺序引发逻辑不一致。例如转账场景:扣款和记账必须原子执行。
- 用一个
'readwrite'事务操作所有相关对象仓库 - 避免先在一个事务里更新 A,再另起事务更新 B —— 中间若页面崩溃,A 已改而 B 未动
- Dexie.js 等库可进一步简化,它自动包装 Promise 并确保事务内所有 await 操作属于同一上下文











