为什么IndexedDB缓存数据在页面刷新后丢失了?
大家好,我在用IndexedDB存用户操作记录时遇到怪事,存完数据马上能读到,但页面刷新后就全没了。明明加了transaction持久化参数啊!
具体场景是这样的:todos列表的缓存,我按教程写了个存储函数:
function saveTodos(todos) {
const request = indexedDB.open('todoDB', 1);
request.onsuccess = () => {
const db = request.result;
const tx = db.transaction(['todos'], 'readwrite');
const store = tx.objectStore('todos');
store.put(todos);
tx.oncomplete = () => db.close();
};
}
存数据时用的是saveTodos({items: ['buy milk']}),立即读能拿到数据。但刷新页面后查询就空了,检查浏览器应用面板也看不到数据库。试过改版本号、清空缓存、不同浏览器都一样。难道IndexedDB默认不会持久化存储吗?
关键点在于:indexedDB.open('todoDB', 1) 这个操作是异步的,它会触发 onupgradeneeded 回调来创建/升级 object store,但你代码里压根没处理这个回调——也就是说,第一次运行时可能 object store 根本没建起来,数据自然没地方存;页面一刷新,浏览器发现数据库不存在或者结构不匹配,就重置了。
你得把 onupgradeneeded 补上,确保 store 被正确创建。比如:
另外注意两点:一是 put 操作需要有主键,我上面加了个 id 字段;二是别手抖把 keyPath 写错,否则写入可能静默失败。还有个小技巧:开发时可以在 onsuccess 里加个 console.log(db.objectStoreNames) 看看 store 是不是真的建好了。
最后别用 db.close(),除非你确定后面不会再用——一般 IndexedDB 连接是全局复用的,关了下次还得重新 open,反而容易丢数据。
解决方法是,在
onupgradeneeded事件里创建对象存储空间(object store),而不是在每次打开时都创建。如果对象存储已经存在,就不要再重复创建了。修改后的代码如下:
另外提醒一下:
1.
todos数据的结构要符合 IndexedDB 的要求,记得转义特殊字符。2. 如果涉及到敏感数据(比如用户操作记录),IndexedDB 不适合存储,因为它是客户端存储,容易被篡改或读取。可以考虑加密后再存储,或者干脆用后端保存。
3. 测试时别频繁更改数据库版本号,这会导致数据丢失。改动前想清楚逻辑。
这样改完再试试,应该就没问题了。