首页app攻略indexeddb使用 indexdb如何存储复杂对象

indexeddb使用 indexdb如何存储复杂对象

圆圆2025-07-28 22:01:25次浏览条评论

IndexedDB:管理动态对象存储与数据分区策略 论文讨论了在IndexedDB中动态添加对象存储(Object) Store)的挑战,特别是createObjectStore方法只能在onupgradeneeded事件中调用的限制。针对在运行时根据需求创建不同存储的需求,强调修改数据库模式(Schema)并不是最佳实践。相反,建议采用在单个对象存储内部通过数据属性(如IndexedDB模式变更机制解析

indexeddb是一个强大的客户端构造数据方案,其核心概念是数据库(database)和对象存储(object) store)。修改对象存储相似关系型数据库中的表,用于存储键值对数据。indexeddb的模式(schema)管理严格,任何对数据库结构的更高,例如删除、或对象存储,都必须在idbopendbrequest的onupgradeneeded回调函数中进行。

onupgradeneeded事件只在以下两种情况被触发:首次创建数据库时。当使用比当前数据库版本的版本号打开数据库时。

这意味着,如果添加新的对象存储,就必须通过递增的数据库版本号来触发此事件。在成功回调中尝试调用db.createObjectStore()会导致运行时错误,因为此时数据库连接已处于稳定状态,不允许进行模式修改。

开发者经常会遇到一种需求:希望在运行时根据不同的“命名空间”或“类型”动态创建或不同的对象存储,例如实现一个类似于localStorage但支持多种独立存储空间的可选版本。

class LocalStorageAsync { #database; constructor(storeName = 'default') { const dbName = 'LocalStorageAsyncDB'; // 首次打开或版本升级时处理模式 const openRequest = indexedDB.open(dbName, 1); // 初始版本号为1 openRequest.onupgradeneeded = (event) =gt; { const db = event.target.result; // 在这里创建或修改对象存储 if (!db.objectStoreNames.contains('dataStore')) { db.createObjectStore('dataStore', { keyPath: 'id', autoIncrement: true }); } }; this.#database = new Promise((resolve,reject) =gt; { openRequest.onsuccess = (event) =gt; { const db = event.target.result; // 这里不能创建新的对象存储 // if (!db.objectStoreNames.contains(storeName)) { // db.createObjectStore(storeName); // 错误:不能在 onsuccess 中调用 // }resolve(db); }; openRequest.onerror = (event) =gt; { console.error(quot;IndexedDB error:quot;, event.target.errorCode);reject(event.target.error); }; }); } // getItem, setItem 等方法将操作 #database async getItem(storeName, key) { const db = wait this.#database; const transaction = db.transaction(['dataStore'], 'readonly'); const store = transaction.objectStore('dataStore'); // 假设数据结构为 { id: 'some_key', storeName: 'foo', value: 'bar' } const request = store.get(key); // 如果key是复合的,需要索引或删除 return new Promise((resolve,reject) =gt; { 请求.onsuccess = (事件)=gt; { co

nst item = event.target.result; // 筛选出特定 storeName 的数据 if (item amp;amp; item.storeName === storeName) { resolve(item.value); } else { resolve(null); } }; request.onerror = (event) =gt; rejection(event.target.error); }); } async setItem(storeName, key, value) { const db = await this.#database; const transaction = db.transaction(['dataStore'], 'readwrite'); const store = transaction.objectStore('dataStore'); // 存储时带上 storeName 属性 const dataToStore = { id: key, storeName: storeName, value: value }; const request = store.put(dataToStore); return new Promise((resolve, rejection) =gt; { request.onsuccess = () =gt; resolve(); request.onerror = (event) =gt; return(event.target.error); }); }}// 使用async function testLocalStorageAsync() 的示例 { const defaultStore = new LocalStorageAsync('default'); wait defaultStore.setItem('default', 'myKey', 'myValue'); console.log('默认存储值:', wait defaultStore.getItem('default', 'myKey')); const fooStore = new LocalStorageAsync('foo'); // 此时不会创建新的对象存储 wait fooStore.setItem('foo', 'anotherKey', 'anotherValue'); console.log('Foo store value:', wait fooStore.getItem('foo', 'anotherKey'));}testLocalStorageAsync();登录后复制避免动态模式变更的策略

正如问题中提到的,尝试在成功回调中通过“虚构”的bumpVersion方法来升级需要是不可能的。IndexedDB的设计哲学是模式(Schema)相对稳定,不应频繁刷新。

为了实现数据分散而避免间隔模式,推荐的策略是在单个或少数几个对象存储内部进行数据管理:

使用数据属性修改进行分区:这是最推荐和灵活的方法。创建一个或少数几个通用的对象存储(例如,命名为dataStore)。在存储中的每个数据根据当时的情况,方便添加一个额外的属性(如storeName或type),用于标识该数据所属的逻辑分区。优点:数据库模式稳定,在需要升级时进行分区触发。简化数据库管理和版本控制。所有数据集中管理,可以备份和迁移。隐藏:隐藏查询特定的数据时,可能需要高效遍历或创建索引。对于大型数据集,需要为storeName属性创建索引以优化查询性能。

示例代码(基于上述LocalStorageAsync的优化):在LocalStorageAsync的构造函数中,我们只创建了一个名为dataStore的对象则。getItem和setItem方法通过在存储的数据对象中storeName属性来区分不同的存储逻辑。为了查询,建议为storeName属性创建索引。

// 在 onupgradeneeded 中为 storeName 属性创建索引openRequest.onupgradeneeded = (event) =gt; { const db = event.target.result; if (!db.objectStoreNames.contains('dataStore')) { const store = db.createObjectStore('dataStore', { keyPath: 'id' }); // 为 storeName 属性创建索引,允许重复值 store.createIndex('byStoreName', 'storeName', { unique: false }); }};// ... getItem 方法中使用索引异步 getItem(storeName, key) { const db = wait this.#database; const transaction = db.transaction(['dataStore'], 'readonly'); const store = transaction.objectStore('dataStore'); const index = store.index('byStoreName'); // 获取索引 // 使用索引和 keyPath 查询常量请求= index.get(IDBKeyRange.only(storeName)); // 查询特定 storeName 的数据 // 返回注意:这里需要进一步过滤 key,因为 index.get(storeName) 可能会产生多个结果 // 更直接的方式是使用复合键或在应用程序层过滤 // 对于简单的键值存储,如果可能的话,我们可能需要迭代或依赖复合键 // 对于简单的情况,一个简单的 get(key) 后跟 storeName 检查通常就足够了。 const directRequest = store.get(key); // 先按主键获取 return new Promise((resolve,reject) =gt; { directRequest.onsuccess = (event) =gt; { const item = event.target.result; if (item amp;amp; item.storeName === storeName) {resolve(item.value); } else {resolve(null); } }; directRequest.onerror = (event) =gt; reject(event.target.error); });}// ... setItem方法保持不变登录后复制

使用复合键(Compound Key)

s):如果你的数据模型允许,可以将storeName和key组合成一个复合键作为主键。这样可以直接通过复合键进行高效查找。优点:查询效率高,直接定位数据。缺点:其结构可能变得复杂,不适用于所有场景。

示例://在onupgradeneeded中创建对象存储时,不指定keyPath,而是手动管理键 const store = db.createObjectStore('dataStore'); // 无 keyPath// setItem 时async setItem(storeName, key, value) { const db = wait this.#database; const transaction = db.transaction(['dataStore'], 'readwrite'); const store = transaction.objectStore('dataStore'); const compositeKey = [storeName, key]; // 复合键 const dataToStore = { value: value }; // 存储的数据 const request = store.put(dataToStore, compotoKey); // 使用复合键存储 // ...}// getItem 时async getItem(storeName, key) { const db = wait this.#database; const transaction = db.transaction(['dataStore'], 'readonly'); const store = transaction.objectStore('dataStore'); const compositeKey = [storeName, key]; const request = store.get(compositeKey); // 使用复合键查询 // ...}登录后复制

请注意,IndexedDB的复合键要求键是备份,而有效的备份中的事情的每个元素都是键类型。注意与总结Schema稳定性优先:尽量保持IndexedDB的模式稳定。间隔的onupgradeneeded触发不仅会增加代码复杂性,还可能导致用户数据迁移的风险和性能首先。数据分区逻辑:如果需要逻辑上的数据分区,优先考虑在数据对象内部添加属性标识(如storeName、type等),并通过索引来优化查询。性能考量:对于大型数据集,为属性创建索引索引,数组全表扫描。 当使用onupgradeneeded时: onupgradeneeded应该用于真正的数据库结构变更,例如添加新的数据类型、重构现有数据而不模型或引入新的功能模块,是为了简单的逻辑数据分区。版本管理:当确实需要数据库修改模式时,一定要严格管理数据库版本号,并编写健壮的迁移逻辑。

通过采用上述策略,开发者可以在不间隔修改IndexedDB模式的底层下,灵活地管理和应用程序数据,从而构建更稳定、高效的Web应用。

以上就是IndexedDB:管理动态对象存储与数据分区策略的详细内容,更多请关注乐哥常识网其他相关文章!

IndexedDB:
荐片app怎么看不了 荐片搜索不了
相关内容
发表评论

游客 回复需填写必要信息