针对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('数据库未打开')
            }
        })
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/718938.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[WTL/Win32]_[中级]_[MVP架构在实际项目中应用的地方]

场景 在开发Windows和macOS的界面软件时,Windows用的是WTL/Win32技术,而macOS用的是Cocoa技术。而两种技术的本地语言一个主打是C,另一个却是Object-c。界面软件的源码随着项目功能增多而增多,这就会给同步Windows和macOS的功能造成很大负担…

Aigtek高压放大器在柔性爬行机器人驱动性能研究中的应用

实验名称:柔性爬行机器人的材料测试 研究方向:介电弹性体的最小能量结构是一种利用DE材料的电致变形与柔性框架形变相结合设计的新型柔性驱动器,所谓最小能量是指驱动器在平衡状态时整个系统的能量最小,当系统在外界的电压刺激下就…

开发一个python工具,pdf转图片,并且截成单个图片,然后修整没用的白边

今天推荐一键款本人开发的pdf转单张图片并截取没有用的白边工具 一、开发背景: 业务需要将一个pdf文件展示在前端显示,但是基于各种原因,放弃了h5使用插件展示 原因有多个,文件资源太大加载太慢、pdf展示兼容性问题、pdf展示效果…

应急便携式气象观测站

TH-BQX5自然灾害,如台风、暴雨、洪涝、干旱等,给人们的生命财产安全带来了巨大威胁。在应对这些灾害时,准确的气象观测数据是制定有效应对策略的基础。近年来,应急便携式气象观测站在自然灾害的监测和预警中发挥了越来越重要的作用…

在 Blazor 中在子组件和父组件之间共享数据

介绍 可以在Blazor 中创建一个子组件并在另一个组件中重用它。我们将非常轻松地在这些组件之间共享数据。我们将创建一个自定义文本框作为子组件。此自定义文本框将显示文本框中的当前字符数,并在需要时限制字符总数。我将逐步解释所有操作。 在 Visual Studio 中…

购物App需要进行软件测试吗?包括哪些测试内容?

随着移动互联网的飞速发展,购物App在人们的日常生活中扮演着越来越重要的角色。然而,由于App开发的复杂性和用户对于购物体验的高要求,保证App的质量成为了一项重要的任务。而软件测试作为确保App质量的关键环节,也日益受到重视。…

文件操作(1)(C语言版)

前言: 为什么要学习文件操作: 1、如果大家写过一些代码,当运行结束的时候,这些运行结果将不复存在,除非,再次运行时这些结果才能展现在屏幕上面,就比如之前写过的通讯录。 现实中的通讯录可以保…

智游剪辑手机版发布!

耗时一个多月,手机版终于开发的差不多了,下面带大家一起来看下效果咋样吧! 功能介绍 打开应用就可以直接看到我们的所有功能了,支持分类查看和关键词搜索功能,每个功能都可以查看帮助教程和收藏,点击即可进…

Day40

Day40 监听器 概念: 监听器用于监听web应用中某些对象信息的创建、销毁、增加,修改,删除等动作的 发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用 监听器对象中的方法。 常用于统计在线…

AWS——01篇(AWS入门 以及 AWS之EC2实例及简单实用)AWS

AWS——01篇(AWS入门 以及 AWS之EC2实例及简单实用) 1. 前言 2. 创建AWS账户 3. EC2 3.1 启动 EC2 新实例 3.1.1 入口 3.1.2 设置名称 选择服务 3.1.3 创建密钥对 3.1.4 网络设置——安全组 3.1.4.1 初始设置 3.1.4.2 添加安全组规则(开放新…

0X0-基于Sklearn的机器学习入门:聚类(上)

本节及后续章节将介绍深度学习中的几种聚类算法,所选方法都在Sklearn库中聚类模块有具体实现。本节为上篇,将介绍几种相对基础的聚类算法,包括K-均值算法和均值漂移算法。 目录 X.1 聚类概述 X.1.1 聚类的种类 X.1.2 Sklearn聚类子模块 …

【JVM结构、JVM参数、JVM垃圾回收】

JVM:Java Virtual Machine java虚拟机 虚拟机:使用软件技术模拟出与具有完整硬件系统功能、运行在一个隔离环境中的计算机系统。 JVM官方文档:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html java 一些命令 javac 将文件编…

【C++入门(3)】函数重载、引用

一、函数重载 1、函数重载概念 函数重载是指在同一作用域中,具有不同形参列表(参数的 个数 或 类型 或类型顺序 不同)的同名函数。 C语言中不允许同名函数的存在,如果一个程序中有两个函数的函数名完全相同,就会报错…

C#(C Sharp)学习笔记_多态【十九】

前言 个人觉得多态在面向对象编程中还比较重要的,而且不容易理解。也是学了一个下午,才把笔记写得相对比较完善,但仍欠缺一些内容。慢慢来吧…… 什么是多态? 基本概念 在编程语言和类型论中,多态(Poly…

2024最新版Node.js下载安装及环境配置教程(非常详细)

一、进入官网地址下载安装包 官网:Node.js — Run JavaScript Everywhere 其他版本下载:Node.js — Download Node.js (nodejs.org) 选择对应你系统的Node.js版本 二、安装程序 (1)下载完成后,双击安装包&#xf…

OpenGL Super Bible 7th-Primitives, Pipelines, and Pixels图元、渲染管线与像素

简介 本文的原版为《OpenGL Super Bible 7th》,是同事给我的,翻译是原文+译文的形势。文章不属于机器直译,原因在于语言不存在一一对应的关系,我将尽可能的按照中国人看起来舒服的方式来翻译这些段子,如果段子让你感到身心愉悦,那还劳烦点个关注,追个更。如果我没有及时…

从0进入微服务需要了解的基础知识

文章目录 系统架构演化过程为什么要了解系统架构的演化过程技术发展认知技术选型与创新 演变过程单体架构分层-分布式集群微服务 分布式\集群\微服务 微服务中的核心要素-拆分原则项目拆分与复杂度微服务的拆分维度有哪些小结 微服务中的核心要素服务化进行拆分后一定是微服务&…

MFC扩展库BCGControlBar Pro v35.0新版亮点:重新设计的工具栏编辑器等

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中,并为您节省数百个开发和调试时间。 BCGControlBar专业版 v35.0已全新发布了,这个版本改进类Visual Studio 2022的视觉主题、增强对多个…

ChatGPT付费创作系统V3.0.2独立版 WEB+H5+小程序端 (H5端界面美化+Pika视频作品广场+SunoAI 文生歌)系统部署教程

播播资源GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序,是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。当前全民热议ChatGPT,流量超级大,引流不要太简单!一键下单即可拥有自己的GPT!无限…

MinIO Enterprise Cache:实现超性能的分布式 DRAM 缓存

随着计算世界的发展和 DRAM 价格的暴跌,我们发现服务器配置通常配备 500GB 或更多的 DRAM。当您处理大型部署时,即使是那些具有超高密度 NVMe 驱动器的部署,这些服务器上的服务器数量乘以 DRAM 也会迅速增加,通常达到几 TB。该 DR…