针对indexedDB的简易封装

连接数据库

我们首先创建一个DBManager类,通过这个类new出来的对象管理一个数据库
具体关于indexedDB的相关内容可以看我的这篇博客
indexedDB

class DBManager{
    
}

我们首先需要打开数据库,打开数据库需要数据库名和该数据库的版本

constructor(dbName, version) {
    this.dbName = dbName;
    this.version = version;
    this.db = null
}

在constructor中我们先初始化数据库相关信息,dbName为该对象管理的数据库的数据库名,version为该数据库的版本,db为该数据库的IDBDatabase对象
现在我们开始实现openDB方法

openDB() {
    return new Promise((resolve, reject) => {
        const cmd = indexedDB.open(this.dbName, this.version)
        cmd.onsuccess = (event) => {
            console.log('数据库打开成功')
            this.db = event.target.result
            resolve(this.db)
        }
        cmd.onerror = (event) => {
            console.log('数据库打开失败')
            reject(event.target.error)
        }
    })
}

因为打开数据库涉及i/o操作,所以是异步的,所以我们需要返回一个Promise

关闭数据库

当数据库使用完毕,为了节省资源,我们可以选择断开数据库的连接

closeDB() {
    if (this.db) {
        console.log('关闭数据库')
        this.db.close()
        this.db = null
    }
}

删除数据库

如果数据库某一天不在使用,我们可以选择删除这个数据库来节省资源

deleteDB() {
    return new Promise((resolve, reject) => {
        const cmd = indexedDB.deleteDatabase(this.dbName)
        cmd.onsuccess = (event) => {
            console.log('数据库删除成功')
            resolve()
        }
        cmd.onerror = (event) => {
            console.log('数据库删除失败')
            reject(event.target.error)
        }
    })
}

同样,删除数据库是异步的,我们需要返回一个Promise

我们接下来来测试一下

(async function () {
    const db = new DBManager("student", 1)
    await db.openDB()
    await db.closeDB()
    await db.deleteDB()
})()

测试
需要注意的是,我们在删除数据库之前必须先断开数据库连接

创建对象仓库

我们接下来需要实现创建对象的方法

createStore(storeName, keyPath, keys) {
    return new Promise((resolve, reject) => {
        if (this.db) {
            console.log('添加存储仓库', storeName)
            const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })
            if (keys) {
                keys.forEach(key => {
                    store.createIndex(key, key, { unique: key === keyPath ? true : false })
                })
            }
            resolve(this.db)
        } else {
            reject('数据库未打开')
        }
    })
}

但是如果我们直接通过调用createStore来创建对象仓库的话浏览器会报错
报错
这是因为针对对象仓库的操作是需要放在db.onupgradeneeded的回调中,所以我们不能直接这么写

数据库的更新

我们可以用一个更新方法来手动触发onupgradeneeded这个事件

updateDB(callback) {
    return new Promise(async (resolve, reject) => {
        console.log('数据库升级')
        if (this.db) {
            this.closeDB()
            this.version += 1
            await this.openDB(callback)
            resolve(this.db)
        }
        else {
            reject('数据库未打开')
        }
    })
}
openDB(callback) {
    return new Promise((resolve, reject) => {
        const cmd = indexedDB.open(this.dbName, this.version)
        cmd.onsuccess = (event) => {
            console.log('数据库打开成功')
            this.db = event.target.result
            resolve(this.db)
        }
        cmd.onerror = (event) => {
            console.log('数据库打开失败')
            reject(event.target.error)
        }
        if (callback) {
            cmd.onupgradeneeded = (event) => {
                this.db = event.target.result
                callback(event)
            }
        }
    })
}

update方法通过调用close和open方法更新数据库,同时将对对象仓库的操作封装成函数传入update方法中,再将这个函数放入open方法中,open方法中通过判断是否传入参数来判断是否需要监听onupgradeneeded事件,因为当用户第一次创建数据库的时候会触发这个事件,而第一次的时候我们是不需要监听的

接下来我们重新处理下createStore里的逻辑

createStore(storeName, keyPath, keys) {
    return new Promise(async (resolve, reject) => {
        if (this.db) {
            await this.updateDB((event) => {
                console.log('添加存储仓库', storeName)
                const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })
                if (keys) {
                    keys.forEach(key => {
                        store.createIndex(key, key, { unique: key === keyPath ? true : false })
                    })
                }
            })
            resolve(this.db)
        } else {
            reject('数据库未打开')
        }
    })
}

接下来我们再来测试一下

(async function () {
    const db = new DBManager("student", 1)
    await db.openDB()
    await db.createStore("student", "id", ['id', 'name', 'age', 'score'])
    await db.closeDB()
    await db.deleteDB()
})()

测试

为什么是先打印添加存储仓库,后打印数据库打开?因为当IDBDatabase对象同时出发onsuccess和onupgradeneeded事件时,会先执行onupgradeneeded的回调,然后执行onsuccess中的回调

数据记录的操作

我们接下来实现关于数据记录的方法

增加数据

增加数据记录的逻辑较为简单,调用indexedDB提供的add方法就行

insert(storeName, data) {
    return new Promise((resolve, reject) => {
        if (this.db) {
            const transaction = this.db.transaction(storeName, 'readwrite')
            const store = transaction.objectStore(storeName)
            const cmd = store.add(data)
            cmd.onsuccess = (event) => {
                console.log('插入数据成功')
                resolve(event.target.result)
            }
            cmd.onerror = (event) => {
                console.log('插入数据失败')
                reject(event.target.error)
            }
        } else {
            reject('数据库未打开')
        }
    })
}

我们来测试一下

(async function () {
    const db = new DBManager("student", 1)
    await db.openDB()
    await db.createStore("student", "id", ['id', 'name', 'age', 'score'])
    await db.insert("student", { id: 1, name: "张三", age: 18, score: 90 })
    await db.insert("student", { id: 2, name: "李四", age: 20, score: 56 })
    await db.closeDB()
    await db.deleteDB()
})()

测试

查询数据

查询数据我们需要根据不同的查询方式来实现不同的方法

  1. 通过key查询

    queryByKey(storeName, value) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.get(value)
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    
  2. 查询全部数据记录

    queryAll(storeName) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.getAll()
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    
  3. 通过游标查询

    queryByCursor(storeName, range, direction = "next") {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cursor = range ? store.openCursor(range, direction) : store.openCursor()
                const result = []
                cursor.onsuccess = (event) => {
                    const cursor = event.target.result
                    if (cursor) {
                        result.push(cursor.value)
                        cursor.continue()
                    } else {
                        console.log('查询数据成功')
                        resolve(result)
                    }
                }
                cursor.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    
  4. 通过指定key-value查询

    queryByIndex(storeName, indexName, value) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.index(indexName).get(value)
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    

我们现在来测试一下

(async function () {
    const db = new DBManager("student", 1)
    await db.openDB()
    await db.createStore("student", "id", ['id', 'name', 'age', 'score'])
    await db.insert("student", { id: 1, name: "张三", age: 18, score: 90 })
    await db.insert("student", { id: 2, name: "李四", age: 20, score: 56 })
    await db.insert("student", { id: 3, name: "王五", age: 19, score: 80 })
    await db.insert("student", { id: 4, name: "赵六", score: 70 })
    const result = await db.queryByIndex("student", "age", 18)
    console.log(result)
    const result2 = await db.queryByKey("student", 3)
    console.log(result2)
    const result3 = await db.queryByCursor("student")
    console.log(result3)
    const result4 = await db.queryByCursor("student", IDBKeyRange.only(4))
    console.log(result4)
    const result5 = await db.queryAll("student")
    console.log(result5)
    await db.closeDB()
    await db.deleteDB()
})()

测试

更新数据

更新数据记录也是通过调用indexedDB中的put方法来实现

update(storeName, key, data) {
    return new Promise((resolve, reject) => {
        if (this.db) {
            const transaction = this.db.transaction(storeName, 'readwrite')
            const store = transaction.objectStore(storeName)
            const cmd = store.put(data)
            cmd.onsuccess = (event) => {
                console.log('更新数据成功')
                resolve(event.target.result)
            }
            cmd.onerror = (event) => {
                console.log('更新数据失败')
                reject(event.target.error)
            }
        } else {
            reject('数据库未打开')
        }
    })
}

删除数据

更新数据记录也是通过调用indexedDB中的delete方法来实现

delete(storeName, key) {
    return new Promise((resolve, reject) => {
        if (this.db) {
            const transaction = this.db.transaction(storeName, 'readwrite')
            const store = transaction.objectStore(storeName)
            const cmd = store.delete(key)
            cmd.onsuccess = (event) => {
                console.log('删除数据成功')
                resolve(event.target.result)
            }
            cmd.onerror = (event) => {
                console.log('删除数据失败')
                reject(event.target.error)
            }
        } else {
            reject('数据库未打开')
        }
    })
}

完整代码

最后我们来看一下完整代码

class DBManager {
    constructor(dbName, version) {
        this.dbName = dbName;
        this.version = version;
        this.db = null
    }
    openDB(callback) {
        return new Promise((resolve, reject) => {
            const cmd = indexedDB.open(this.dbName, this.version)
            cmd.onsuccess = (event) => {
                console.log('数据库打开成功')
                this.db = event.target.result
                resolve(this.db)
            }
            cmd.onerror = (event) => {
                console.log('数据库打开失败')
                reject(event.target.error)
            }
            if (callback) {
                cmd.onupgradeneeded = (event) => {
                    this.db = event.target.result
                    callback(event)
                }
            }
        })
    }
    closeDB() {
        if (this.db) {
            console.log('关闭数据库')
            this.db.close()
            this.db = null
        }
    }
    deleteDB() {
        return new Promise((resolve, reject) => {
            const cmd = indexedDB.deleteDatabase(this.dbName)
            cmd.onsuccess = (event) => {
                console.log('数据库删除成功')
                resolve()
            }
            cmd.onerror = (event) => {
                console.log('数据库删除失败')
                reject(event.target.error)
            }
        })
    }
    updateDB(callback) {
        return new Promise(async (resolve, reject) => {
            console.log('数据库升级')
            if (this.db) {
                this.closeDB()
                this.version += 1
                await this.openDB(callback)
                resolve(this.db)
            }
            else {
                reject('数据库未打开')
            }
        })
    }
    createStore(storeName, keyPath, keys) {
        return new Promise(async (resolve, reject) => {
            if (this.db) {
                await this.updateDB((event) => {
                    console.log('添加存储仓库', storeName)
                    const store = this.db.createObjectStore(storeName, { keyPath: keyPath, autoIncrement: true })
                    if (keys) {
                        keys.forEach(key => {
                            store.createIndex(key, key, { unique: key === keyPath ? true : false })
                        })
                    }
                })
                resolve(this.db)
            } else {
                reject('数据库未打开')
            }
        })
    }
    deleteStore(storeName) {
        return new Promise(async (resolve, reject) => {
            if (this.db) {
                await this.updateDB((event) => {
                    console.log('删除存储仓库', storeName)
                    const store = this.db.deleteObjectStore(storeName)
                })
                resolve(this.db)
            } else {
                reject('数据库未打开')
            }
        })
    }
    insert(storeName, data) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readwrite')
                const store = transaction.objectStore(storeName)
                const cmd = store.add(data)
                cmd.onsuccess = (event) => {
                    console.log('插入数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('插入数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    update(storeName, key, data) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readwrite')
                const store = transaction.objectStore(storeName)
                const cmd = store.put(data)
                cmd.onsuccess = (event) => {
                    console.log('更新数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('更新数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    delete(storeName, key) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readwrite')
                const store = transaction.objectStore(storeName)
                const cmd = store.delete(key)
                cmd.onsuccess = (event) => {
                    console.log('删除数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('删除数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    queryByKey(storeName, value) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.get(value)
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    queryAll(storeName) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.getAll()
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    queryByIndex(storeName, indexName, value) {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cmd = store.index(indexName).get(value)
                cmd.onsuccess = (event) => {
                    console.log('查询数据成功')
                    resolve(event.target.result)
                }
                cmd.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
    queryByCursor(storeName, range, direction = "next") {
        return new Promise((resolve, reject) => {
            if (this.db) {
                const transaction = this.db.transaction(storeName, 'readonly')
                const store = transaction.objectStore(storeName)
                const cursor = range ? store.openCursor(range, direction) : store.openCursor()
                const result = []
                cursor.onsuccess = (event) => {
                    const cursor = event.target.result
                    if (cursor) {
                        result.push(cursor.value)
                        cursor.continue()
                    } else {
                        console.log('查询数据成功')
                        resolve(result)
                    }
                }
                cursor.onerror = (event) => {
                    console.log('查询数据失败')
                    reject(event.target.error)
                }
            } else {
                reject('数据库未打开')
            }
        })
    }
}

相关推荐

  1. ts封装浏览器indexedDB

    2024-06-18 10:02:04       32 阅读
  2. <span style='color:red;'>IndexedDB</span>

    IndexedDB

    2024-06-18 10:02:04      55 阅读
  3. axios简单封装即使用

    2024-06-18 10:02:04       61 阅读
  4. C# 【WPF】之 INotifyPropertyChanged简单封装

    2024-06-18 10:02:04       67 阅读
  5. 腾讯地图简单功能封装

    2024-06-18 10:02:04       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 10:02:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 10:02:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 10:02:04       82 阅读
  4. Python语言-面向对象

    2024-06-18 10:02:04       91 阅读

热门阅读

  1. WDF驱动开发-注册表项

    2024-06-18 10:02:04       32 阅读
  2. 15.2 测试-网格测试、基准测试与测试覆盖率

    2024-06-18 10:02:04       27 阅读
  3. WPF 布局控件 Grid表格

    2024-06-18 10:02:04       24 阅读
  4. C++值单例模式与auto_ptr

    2024-06-18 10:02:04       29 阅读
  5. MySQL触发器基本结构

    2024-06-18 10:02:04       31 阅读
  6. 从零开始精通Onvif之图片抓拍

    2024-06-18 10:02:04       28 阅读
  7. PHP之EOF定界符

    2024-06-18 10:02:04       26 阅读
  8. 科研辅助工具

    2024-06-18 10:02:04       25 阅读
  9. Unity与Android交互通信系列(6)

    2024-06-18 10:02:04       27 阅读
  10. idea git stash报错Too many revisions specified

    2024-06-18 10:02:04       31 阅读
  11. 创建单例模式的六种方式

    2024-06-18 10:02:04       33 阅读
  12. jQuery 常用函数解析

    2024-06-18 10:02:04       33 阅读