前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库IndexedDB 事务原子性保证
浏览浏览器存储与离线数据

IndexedDB 事务的原子性如何保证?

IndexedDB 事务的原子性由事务机制保证:事务内任一操作失败且未屏蔽错误时,整个事务中止并回滚所有变更,数据不会部分写入。

前端进阶之旅 · 一题精讲更新于 2026.09.05
浏览器#存储与离线数据#离线应用#数据库事务
先看核心答案
理解线索

事务失败与中止

  1. 活跃状态请求入队并依次执行
  2. 错误传播未处理错误冒泡到事务
  3. 自动回滚事务中止撤销所有写入

只有 request 错误事件未调用 preventDefault 时才会自动中止。

核心回答

先记住这个答案

IndexedDB 的 readwrite 或 readonly 事务由 IDBTransaction 管理。当某个请求发出错误且未阻止其默认行为(即未调用 event.preventDefault())时,会触发事务中断(abort),浏览器自动回滚该事务内所有已执行的写入。实现方式是每个事务有活跃期,若请求失败并冒泡到事务层,则中止并撤销修改。为确保原子性,开发者不应在 onerror 中误调 preventDefault() 阻止默认中止行为,除非有意识地部分回滚。

  • 事务内操作失败默认终止并回滚
  • 未阻止错误默认行为才会触发自动回滚
  • 回滚不包含事务提交后的崩溃恢复

事务原子性的内部保障机制

当调用 db.transaction(storeNames, 'readwrite') 创建事务时,浏览器为其分配一个作用域。事务进入活跃状态,期间发出的 add、put、delete 等请求按顺序排队。只要事务仍活跃,请求结果会不断触发相应事件。若某个请求抛出错误(例如主键冲突或约束失败),该错误会作为 IDBRequest 的 error 事件派发。如果该请求的 onerror 处理函数没有调用 event.preventDefault(),错误会冒泡到 IDBTransaction 对象上,导致事务被标记为失败。

事务被标记失败后,浏览器立即中止事务并触发 abort 事件。此时所有已经写入对象存储的数据都会被回滚,仿佛这个事务从未执行过。这也意味着事务内后续尚未发出的请求不会执行,队列被清空。整个机制确保了资源不会处于中间状态。需要明确的是,这里回滚的对象是“数据变更”,包括新增、修改、删除的内容;而对象存储的结构变更(如建表)不在普通事务范围内,只有 versionchange 事务才负责 schema 调整。

批量导入时部分失败的整体回滚

假设一个管理系统需要导入用户列表,业务要求要么全部成功,要么全部不导入。代码在一个 readwrite 事务中循环删除旧用户名索引,再插入新记录。例如先 store.clear(),然后逐个 store.put。若第 10 条数据违反了唯一索引约束,该 put 请求的错误被默认处理,整个事务立刻中止,之前的 clear 和第 1–9 条 put 全部撤销。最终对象存储仍然保留原来的旧数据,没有出现“清空一半但新数据没有写入”的脏状态。开发者只需监听 transaction.onabort,在 UI 中提示“导入失败,数据已回滚”。

这种原子性特别适合需要一致性的批处理。如果不希望全部回滚,则应在每个请求的 onerror 中调用 event.preventDefault() 并自己记录错误,错误冒泡被阻止后事务不会中止。但那样就需要自己维护部分成功的数据,原本的原子性就被放弃了。在实际工程中,优先依赖默认回滚,可编写一个简单的事务包装器,把多次请求封装在 Promise 里,任何失败都 reject 并让事务自动中止,节省大量手动补偿代码。

原子性的失效边界与应对

原子性不是持久性。虽然事务提交时数据已写入,但如果操作系统崩溃或浏览器在事务提交后、数据落盘前崩溃,仍可能丢失整个事务。Firefox 从 40 起放宽了持久性保证以提升性能,complete 事件在数据尚未真正刷盘时也会触发。关键在于“提交成功”不等同于“永久保存”,需要强持久性时应考虑 readwriteflush 非标准模式或在事务外额外验证。这不是原子性失败,而是硬件故障导致的丢数据。

另外,错误处理是边界中的关键。请求的 error 事件如果被 preventDefault() 阻止,事务不会被中止,失败的操作只是该请求作废。例如一个 get 找不到记录并不会触发错误,但某些约束冲突可能因业务需求被吞掉。吞掉后事务继续,后续写入可能依赖失败前的状态,造成逻辑不一致。开发者需明确:事务原子性默认开启,但可通过 preventDefault() 自愿关闭某次失败的中止效果。在敏感场景,最好始终让意外错误冒泡,只对预期错误做针对性处理。

回答前,多想一步

容易答错的地方

把请求错误都视为事务失败
一个请求出错并不必然导致事务回滚。只有错误冒泡到事务且未被 preventDefault() 拦截时才会中止。若在 onerror 里调用 event.preventDefault(),事务继续运行,该请求失败不会触发回滚。
认为‘任一操作失败’包括读取失败
只读事务中的读取操作(如 get)找不到目标记录会正常完成,不视为失败。只有真正发生的错误(如约束冲突、数据损坏)才可能触发中止。
试着用自己的话回答

面试官还会怎么问?

如何区分单个请求失败和事务全部回滚?

监听事务的 onabort,若触发则说明整个事务回滚。单个请求的 onerror 是其自身错误,事务可能因该请求失败而中止,也可能在 preventDefault 后继续。

`versionchange` 事务有原子性吗?

有,versionchange 事务同样具备原子性,且其作用域覆盖所有对象存储。但它与普通读写事务触发时机不同,只能在数据库升级时创建。如果升级过程中出错,数据库结构和数据均保持一致。

如果事务中调用 `abort()` 会发生什么?

调用 IDBTransaction.abort() 会主动中止事务并回滚所有修改,触发 onabort 事件。这可以用于显式撤销基于业务判断的不当操作。

从一道题,走向一组知识

把知识连起来

存储与离线数据

Cookie 的 HttpOnly、Secure 和 SameSite 属性各自解决什么问题?

同属「存储与离线数据」专题,接着看 Cookie HttpOnly Secure SameSite 属性作用 在具体场景中的处理方式。

存储与离线数据

sessionStorage 的数据生命周期与标签页或刷新有什么关系?

同属「存储与离线数据」专题,接着看 sessionStorage 生命周期与标签页刷新 在具体场景中的处理方式。

参考资料

  • Using IndexedDB

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 事务原子性的内部保障机制
  3. 批量导入时部分失败的整体回滚
  4. 原子性的失效边界与应对
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑