indexeddb 缓存股票自选股及行情的核心是合理设计表结构、同步策略与数据校验:拆分为 stocks(存元信息,主键 code)和 quotes(存行情快照,主键 code + timestamp 索引),版本升级需显式定义 store,存前过滤非自选、去重、按时间戳更新,读时优先本地并后台静默刷新。

用 IndexedDB 缓存用户的股票自选股列表及离线行情,核心是把用户选的股票代码、名称、最新价、涨跌幅等数据结构化存进数据库,并在无网络时优先读取本地缓存,有网时再异步更新。关键不在“能不能存”,而在“怎么设计表结构、何时写入、如何同步、怎样避免脏数据”。
设计合理的 Object Store 和数据结构
不要把整个行情对象一股脑塞进去。建议拆成两个 store:
- stocks:存用户自选股元信息(id、code、name、orderIndex),主键用 stockCode(如 "sh600519")
- quotes:存行情快照(code、price、change、time、timestamp),主键也用 code,但加一个 timestamp 字段用于判断新旧
这样分离后,增删自选股只操作 stocks;行情更新只写 quotes,互不影响。quote 数据可带时间戳,方便后续做“过期判定”——比如超过 30 秒未更新就视为陈旧。
初始化数据库并处理升级逻辑
首次打开或版本变更时,必须用 onupgradeneeded 创建/修改 store:
const request = indexedDB.open('StockCache', 2);
request.onupgradeneeded = event => {
const db = event.target.result;
if (!db.objectStoreNames.contains('stocks')) {
db.createObjectStore('stocks', { keyPath: 'code' });
}
if (!db.objectStoreNames.contains('quotes')) {
const quotes = db.createObjectStore('quotes', { keyPath: 'code' });
quotes.createIndex('byTime', 'timestamp', { unique: false });
}
};
注意:版本号只能递增,不能回退;每次改结构都必须 bump version 并在 upgrade 中显式定义,否则旧 store 不会自动适配。
存行情前先校验和去重
从接口拿到行情数组后,别直接 bulkWrite。先做三件事:
- 过滤掉非自选股的行情(防止误存其他股票)
- 对比本地已有 quote 的 timestamp,只保存更新时间更晚的
- 用
IDBKeyRange.bound或游标批量写入,避免单条请求堆积
示例片段:
function saveQuotes(db, quotes) {
const tx = db.transaction(['quotes'], 'readwrite');
const store = tx.objectStore('quotes');
quotes.forEach(q => {
store.put({
code: q.code,
price: q.price,
change: q.change,
time: q.time,
timestamp: Date.now()
});
});
}
读取时优先本地 + 后台静默刷新
页面加载时,先读 stocks 获取用户列表,再用 keys() 批量查 quotes,拼出完整行情。同时发起一次 fetch 请求拉新数据 —— 但不阻塞 UI,成功后再调 saveQuotes 覆盖本地。
如果网络失败,就用本地数据渲染,并显示“数据可能已过期”提示;若用户手动下拉刷新,才弹 toast 提示“正在同步最新行情”。这样既保证秒开,又不牺牲准确性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











