indexedDB 使用小结

因为项目用到了indexedDB存一些数据,就补了一下这方便的资料。踩一下“坑”。如果你还不了解什么是indexedDB,可以先看看这三篇文章入个门。


1.不能动态添加表

indexedDB 中 createObjectStore(类似新增表)和deleteObjectStore(类似删除表)方法只有在onupgradeneeded 中调用。而表有时候又是动态的,所以做了一下的封装。

/**
 * 根据数据库中是否包含表名会自动升级数据库
 * @param dbName         数据库名称
 * @param storeNames     表名-arrays
 * @param version        数据库版本号
 */
export async function openDatabase(dbName, storeNames = [], version = undefined) {
    return new Promise((resolve, reject) => {
        const request = window.indexedDB.open(dbName, version)
        request.onsuccess = (event) => {
            const db = event.target.result

            let isNeedUpdate = false
            for (let i = 0; i < storeNames.length; i++) {
                if (!db.objectStoreNames.contains(storeNames[i])) {
                    isNeedUpdate = true
                    break
                }
            }

            function callback(db) {
                if (db) {
                    resolve(db)
                } else {
                    reject(`can't open ${dbName}`)
                }
            }

            if (isNeedUpdate) {
                const version = db.version + 1
                db.close()
                openDatabase(dbName, storeNames, version).then((db) => {
                    callback(db)
                })
            } else {
                callback(db)
            }
        }
        request.onerror = (e) => {
            reject(e)
        }
        request.onblocked = () => {
            reject(`${dbName} is blocked.`)
        }
        request.onupgradeneeded = (event) => {
            const db = event.target.result
            for (const storeName of storeNames) {
                if (!db.objectStoreNames.contains(storeName)) {
                    db.createObjectStore(storeName, {
                        keyPath: "key"
                        // autoIncrement: true
                    })
                }
            }
        }
    })
}

2.主键不能更新

我的需求是把一个文件列表存入数据库。之前是把文件完整路径作为了主键。但是当遇到修改文件名或移动文件,文件路径就会发生变更的这种情况,就需要更新主键。然而并没有找到这样的方法。

IDBObjectStore.put(item, key)方法用于更新某个主键对应的数据记录,如果对应的键值不存在,则插入一条新的记录。该方法返回一个 IDBRequest 对象。
该方法接受两个参数,第一个参数为新数据,第二个参数为主键,该参数可选,且只在自动递增时才有必要提供,因为那时主键不包含在数据值里面。

所以,我能想到的方案

  1. 先删除记录,再添加。不过就不能算是更新了。
  2. 创建表时,不要使用数据字段为主键,除非你确定以后不会改。使用自增主键。还有修改对应的获取数据的方法。 该方法放弃,如果使用自增字段做主键,然后通过索引字段可以获取数据。但是却拿得不到对应的主键(通过IDBCursor可以获取,但是感觉方法很笨)。拿不到主键还是更新不了数据...卒
阅读 278

推荐阅读