IndexedDB 升级数据库版本并修改存储结构,核心在于严格递增版本号、在 onupgradeneeded 中执行结构变更,且所有操作必须幂等。它不支持自动回滚或跳过中间版本,升级逻辑完全由开发者控制。

IndexedDB 升级数据库版本并修改存储结构,核心在于严格递增版本号、在 onupgradeneeded 中执行结构变更,且所有操作必须幂等。它不支持自动回滚或跳过中间版本,升级逻辑完全由开发者控制。
版本号必须整数递增,不能降级或跳变
每次结构变更(如新增表、加字段、建索引)都需提升版本号,且只能是正整数:v1 → v2 → v3 …… 传入 0、负数、小数或字符串(如 "2")会导致 open 失败或静默报错。
- 首次创建用
indexedDB.open('db', 1) - 后续升级必须显式传入更大整数,例如从 v2 升到 v3 就调用
indexedDB.open('db', 3) - 若传入的版本低于当前库版本,会直接抛
VersionError,数据库打不开
结构变更只能在 onupgradeneeded 中进行
这是唯一合法入口。所有 createObjectStore、createIndex、deleteObjectStore 等操作,都必须放在这里,且只能通过 event.target.result 获取的 db 实例调用。
- 不能在
onsuccess或其他事件里执行建表/建索引,否则报InvalidStateError - 用
oldVersion < 新版本判断是否需要执行某步迁移,而不是===,这样才能支持跨版本升级(如 v1 → v3) - 示例:从 v1 升到 v3 时,既要处理 v1→v2 的变更,也要处理 v2→v3 的变更
迁移代码必须幂等,避免重复执行
因为开发调试或用户多次访问可能反复触发 onupgradeneeded,所以每一步都要检查是否存在再操作。
立即学习“Java免费学习笔记(深入)”;
- 建表前先判断:
if (!db.objectStoreNames.contains('logs')) { db.createObjectStore('logs', { keyPath: 'id' }); } - 建索引前确认:
if (!store.indexNames.contains('byTime')) { store.createIndex('byTime', 'time'); } - 删字段或重命名数据时,建议加迁移标记(如在 DB 中存一个
__migrated_v2键),防止重复跑数据转换逻辑
旧标签页会阻塞升级,需主动监听 versionchange
只要同域名下有另一个页面还连着旧版本数据库,新页面的 onupgradeneeded 就不会触发——而且没有错误提示,是最隐蔽的坑。
- 在
onsuccess后立即绑定:db.onversionchange = () => { db.close(); alert('检测到新版本,请刷新页面'); }; - 不要依赖用户手动关掉旧页;升级逻辑要默认旧连接随时存在
- 提示语应明确,避免用户继续在旧页操作导致数据不一致


















