浏览器本地存储策略之前端数据库: IndexedDB

IndexedDB 介绍

常见存储方式主要有两种:cookie、webStorage(localStorage和sessionStorage),但它们不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。因此,我们可以使用前端数据库来实现。在浏览器上有两种数据库:webSQL和IndexedDB。

IndexedDB是浏览器提供的本地数据库, 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

IndexedDB 具有以下特点:

  1. 键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

  2. 异步。IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

  3. 支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

  4. 同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

  5. 储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。

  6. 支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

IndexedDB的一些基本概念:

  1. 数据库,数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。 IndexedDB数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。

  2. 对象仓库,每个数据库包含若干个对象仓库(object store)。它类似于关系型数据库的表格。

  3. 数据记录,对象仓库保存的是数据记录。每条记录类似于关系型数据库的行,但是只有主键和数据体两部分。主键可以是数据记录里面的一个属性,也可以指定为一个递增的整数编号。

  4. 索引,添加索引后可以使用索引查询数据

  5. 事务,数据记录的读写和删改,都要通过事务完成。事务对象提供error、abort和complete三个事件,用来监听操作结果。

通过类来封装可以提高可读性、 可拓展性、可维护性强

	//  数据库对象
    class MyDataBase {
        constructor(
            database,
            version,
            tablename
        ) {
            this.DATABASE_NAME = database;
            this.VERSION = version;
            this.TABLE = tablename;
        }
        
        //  相关数据库操作
        ...
     }

连接并初始化数据库:

        /**
         * 获取数据库对象
         */
        getDB(dbName, version, table) {
            return new Promise(function (resolve, reject) {
                let request = window.indexedDB.open(dbName, version);
                request.onsuccess = function (e) {
                    // let db = e.target.result;
                    let db = this.result;
                    resolve(db);
                }
                request.onupgradeneeded = function (e) {
                    // 初始化数据库
                    let db = this.result;
                    if (!db.objectStoreNames.contains(table || this.TABLE)) {
                        var objectStore = db.createObjectStore(table || this.TABLE, {
                            autoIncrement: true
                        });
                        // 创建索引
                        // 可以通过索引查询
                        objectStore.createIndex("name", "name", {
                            unique: true
                        });
                        objectStore.createIndex("email", "email", {
                            unique: true
                        });
                    };
                }
            })
        }

获取数据库中某一张表的所有数据记录:

        /**
         * 读取 [db]--[tableName] 下的所有记录
         */
        readAllRecord(db, tableName) {
            return new Promise(function (resolve, reject) {
                let objectStore = db.transaction(tableName).objectStore(tableName);
                let records = [];
                objectStore.openCursor().onsuccess = function (e) {
                    let cursor = e.target.result;
                    if (cursor) {
                        records.push(cursor.value);
                        cursor.continue();
                    } else {
                        resolve({
                            code: 200,
                            data: records
                        })
                    }
                }
                objectStore.openCursor().onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

查找某一条数据(根据数据库表的主键):

        /**
         * 获取 [db]--[tableName]下,主键为 [key] 的某条记录
         */
        getRecord(db, tableName, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName)
                    .objectStore(tableName)
                    .get(key);
                request.onsuccess = function (e) {
                    resolve({
                        code: 200,
                        data: e.target.result
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

根据索引查找数据:

        /**
         * 根据索引所在位置 [_index],获取 [db]--[tableName]下,索引值为 [identify]的某条记录
         */
        getRecordWithIndex(db, tableName, _index, identify) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .index(_index)
                    .get(identify);
                request.onsuccess = function (e) {
                    resolve({
                        code: 200,
                        data: e.target.result
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

向数据库特定表添加一条数据:

        /**
         * 在 [db]--[tableName]中新增一条记录[data]
         */
        addRecord(db, tableName, data) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .add(data);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

修改某一条数据(根据主键):

        /**
         * 将 [db]--[tableName]中,主键为 [key]的数据为,更新为 [data]
         */
        updateRecord(db, tableName, data, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .put(data, key);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    })
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

删除某一条数据(根据主键):

        /**
         * 在 [db]--[tableName]下,删除主键为[key]的记录
         */
        deleteRecord(db, tableName, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .delete(key);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

完整代码:

	//  数据库对象
    class MyDataBase {
        constructor(
            database,
            version,
            tablename
        ) {
            this.DATABASE_NAME = database;
            this.VERSION = version;
            this.TABLE = tablename;
        }

        /**
         * 在 [db]--[tableName]中新增一条记录[data]
         */
        addRecord(db, tableName, data) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .add(data);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 获取 [db]--[tableName]下,主键为 [key] 的某条记录
         */
        getRecord(db, tableName, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName)
                    .objectStore(tableName)
                    .get(key);
                request.onsuccess = function (e) {
                    resolve({
                        code: 200,
                        data: e.target.result
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 根据索引所在位置 [_index],获取 [db]--[tableName]下,索引值为 [identify]的某条记录
         */
        getRecordWithIndex(db, tableName, _index, identify) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .index(_index)
                    .get(identify);
                request.onsuccess = function (e) {
                    resolve({
                        code: 200,
                        data: e.target.result
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 读取 [db]--[tableName] 下的所有记录
         */
        readAllRecord(db, tableName) {
            return new Promise(function (resolve, reject) {
                let objectStore = db.transaction(tableName).objectStore(tableName);
                let records = [];
                objectStore.openCursor().onsuccess = function (e) {
                    let cursor = e.target.result;
                    if (cursor) {
                        records.push(cursor.value);
                        cursor.continue();
                    } else {
                        resolve({
                            code: 200,
                            data: records
                        })
                    }
                }
                objectStore.openCursor().onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 将 [db]--[tableName]中,主键为 [key]的数据为,更新为 [data]
         */
        updateRecord(db, tableName, data, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .put(data, key);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    })
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 在 [db]--[tableName]下,删除主键为[key]的记录
         */
        deleteRecord(db, tableName, key) {
            return new Promise(function (resolve, reject) {
                let request = db.transaction(tableName, "readwrite")
                    .objectStore(tableName)
                    .delete(key);
                request.onsuccess = function () {
                    resolve({
                        code: 200
                    });
                }
                request.onerror = function (e) {
                    reject({
                        code: 0,
                        msg: e.target.error
                    })
                }
            })
        }

        /**
         * 获取数据库对象
         */
        getDB(dbName, version, table) {
            return new Promise(function (resolve, reject) {
                let request = window.indexedDB.open(dbName, version);
                request.onsuccess = function (e) {
                    // let db = e.target.result;
                    let db = this.result;
                    resolve(db);
                }
                request.onupgradeneeded = function (e) {
                    // 初始化数据库
                    let db = this.result;
                    if (!db.objectStoreNames.contains(table || this.TABLE)) {
                        var objectStore = db.createObjectStore(table || this.TABLE, {
                            autoIncrement: true
                        });
                        // 创建索引
                        // 可以通过索引查询
                        objectStore.createIndex("name", "name", {
                            unique: true
                        });
                        objectStore.createIndex("email", "email", {
                            unique: true
                        });
                    };
                }
            })
        }
    }

    // 数据库连接信息
    const connection = {
        database: 'my_database',
        version: '1.0',
        tablename: 'table_user'
    }
    // 获取数据库对象
    const database = new MyDataBase(
        connection.database,
        connection.version,
        connection.tablename
    );

    database.getDB(connection.database, connection.version, connection.tablename).then(db => {
        let data = {
            id: 1,
            name: "张三",
            age: 18,
            email: "[email protected]"
        }

        let data1 = {
            id: 2,
            name: "张三22",
            age: 18,
            email: "[email protected]"
        }

        database.addRecord(db, connection.tablename, data).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        database.addRecord(db, connection.tablename, data1).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        database.readAllRecord(db, connection.tablename).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        // 根据数据库存储数据的主键来查找某一条数据
        database.getRecord(db, connection.tablename, 1).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        // 根据索引为email字段,并且索引值为[email protected] 来查找数据
        database.getRecordWithIndex(db, connection.tablename, "email", "[email protected]").then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        database.updateRecord(db, connection.tablename, { id: 1, name: "李四", age: 18, email: "[email protected]" }, 1).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

        database.deleteRecord(db, connection.tablename, 1).then(res => {
            console.log(res);
        }, err => {
            console.log(err);
        })

    })

你可能感兴趣的:(数据库,javascript,前端)