前端本地储存数据库 IndexedDB 零基础入门知识详解

目录

前言:

1.IndexedDB 简介

2.IndexedDB 使用场景

3.IndexedDB 特点

(1) 非关系型数据库(NoSql)

(2) 持化存储

(3)异步操作

 (4)支持事务

(5) 同源策略

(6)存储容量大

4.IndexedDB 概念补充

①仓库objectStore

②索引index

③游标cursor

④事务

5.IndexedDB 实操

①创建或连接数据库

② 插入数据

③通过主键读取数据 

④通过游标查询数据

⑤通过索引查询数据

⑥通过索引和游标查询数据

⑦通过索引和游标分页查询

⑧更新数据

⑨通过主键删除数据

⑩通过索引和游标删除指定数据

⑪关闭数据库

⑫删除数据库


 

前言:

在浏览器上有两种数据库: webSQL和IndexedDB。但是如果在浏览器上需要用到数据库一般会使用Indexed DB数据库,webSQL基本上已经废弃了。

WebSQL 是一种基于 SQL 的浏览器本地存储技术,在 HTML5 中是一个非标准化技术。虽然 WebSQL 在一些场景下使用起来比较方便,但是由于其不被 W3C 标准化,导致了一些问题:

  1. 浏览器之间的兼容性问题。不同浏览器对 WebSQL 的支持程度不一样,甚至有些浏览器完全不支持,这导致了 WebSQL 在移动端和 PC 端之间的兼容性问题。
  2. 安全性问题。WebSQL 存在一些潜在的安全风险,例如攻击者可以通过注入恶意 SQL 语句来获取用户数据等。
  3. 数据库规模限制。WebSQL 的数据库容量限制是各个浏览器自己实现的,没有一个通用的标准,而且大部分浏览器都对数据库大小进行了限制。

因此,W3C 推出了 IndexedDB 标准,作为 WebSQL 的替代方案,并得到了主流浏览器的支持。IndexedDB 具有更好的跨平台兼容性,安全可靠,支持事务和异步操作等特性,能够更好地应对现代移动端应用和在线数据存储应用的需求。

(前端存储方案有如cookie、sessionstorage等等)


1.IndexedDB 简介

MDN官网是这样解释 Indexed DB的:

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据 (也包括文件/二进制大型对象 (blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

 cookie、localStorage 等存储方式都有存储大小限制,如果数据量很大,且都需要客户端存储时,则使用 IndexedDB 数据库。

会话期 Cookie 持久性 CookiesessionSto
rage
localStora
ge
indexedDBWebsQL
存储大小4kb4kb2.5~10MB2.5~10MB>250MB已废弃
失效时间浏览器关闭自动清除设置过期时间,到
期后清除
浏览器关
闭后清除
永久保存
(除非手
动清除)
手动更新
或删除
已废弃
与服务端交互已废弃
访问策略符合同源策略可以访问符合同源策略可以
访问
符合同源
策略可以
访问
即使同源
也不可相
互访问
符合同源
策略可以
已废弃
访问器
已废弃


2.IndexedDB 使用场景

所有的场景都基于客户端需要存储大量数据的前提下:

  1. 数据可视化等界面,大量数据,每次请求会消耗很大性能。
  2. 即时聊天工具,大量消息需要存在本地。
  3. 其它存储方式容量不满足时,不得已使用 IndexedDB


3.IndexedDB 特点

(1) 非关系型数据库(NoSql)

MySQL等数据库都是关系型数据库,它们的主要特点就是数据都以一张二维表的形式存储,而Indexed DB是非关系型数据库,主要以键值对的形式存储数据。


(2) 持化存储

cookie、localStorage、 sessionStorage 等方式存储的数据当我们清楚浏览器缓存后,这些数据都会被清除掉的,而使用IndexedDB存储的数据则不会,除非手动删除该数据库。


(3)异步操作

 IndexedDB 操作时不会锁死浏览器(异步),用户依然可以进行其他的操作,这与localstorage形成鲜明的
对比,后者是同步的。

 (4)支持事务

IndexedDB 支持事务 (transaction),这意味着一系列的操作步骤之中,只要有一步失败了,整个事务都会取消,数据库回滚的事务发生之前的状态,这和MySQL等数据库的事务类似。

(5) 同源策略

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

(6)存储容量大

IndexedDB最显著的特点之一了,也是不用localStorage等存储方式的最好理由。


4.IndexedDB 概念补充

①仓库objectStore

IndexedDB 它只有仓库 store 的概念,可以把仓库理解为表即可,即一个 store 没有表的概念,是一张表。

②索引index

在关系型数据库当中也有索引的概念,我们可以给对应的表字段添加索引,以便加快查找速率。在IndexedDB 中同样有索引,可以在创建store的时候同时创建索引,在后续对store进行查询的时候即可通过索引来筛选,给某个字段添加索引后,在后续插入数据的过成功,索引字段便不能为空。

③游标cursor

游标是IndexedDB数据库新的概念,可以把游标想象为一个指针,当要查询满足某一条件的所有数据时,就需要用到游标,让游标一行一行的往下走,游标走到的地方便会返回这一行数据,此时便可对此行数据进行判断,是否满足条件。
⭕注意:IndexedDB 查询不像 MySQL等数据库方便它只能通过主键、索引、游标方式查询数据。

④事务

IndexedDB支持事务,即对数据库进行操作时,只要失败了的一致性。都会回滚到最初始的状态,确保数据 


5.IndexedDB 实操

IndexedDB 所有针对仓库的操作都是基于事务的。

①创建或连接数据库

//打开数据库
//@param {object} dbName 数据库的名字
//@param {string} storeName 仓库名称
//@param {string} version 数据库的版本
//@return {object} 该函数会返回一个数据库实例

function openDB(dbName, version = 1) {
    return new Promise((resolve, reject) =>{
        // 兼容浏览器
        var indexedDB =
            window.indexedDB ||
            window.mozIndexedDB ||
            window.webkitIndexedDB ||
            window.msIndexedDB;
        let db;
        // 打开数据库,若没有则会创建
        const request = indexedDB.open(dbName,version);

        //数据库打开成功回调
        request.onsuccess = fuction(evetn){
            db = event.target.result; //数据库对象
            console.log("数据库打开成功");
            resolve(db);
        };
        //数据库打开失败的回调
        request .onerror= function(event){
            console.log("数据库打开报错");
        };

        //数据库有更新时候的回调
        request.onupgradeneeded = function (event){
            // 数据库创建或升级的时候会触发
            console.log("onupgradeneeded");
            db = event.target.result; //数据库对象var objectstore;
            // 创建存储库
            objectstore = db.createobjectstore("signalChat",{
                keyPath:"sequenceId",// 这是主键
                // autoIncrement: true // 实现自增
            });
            // 创建索引,在后面查询数据的时候可以根据索引查        
            objectStore.createIndex("link","link", { unique:false});
            objectstore.createIndex("sequenceId","sequenceId", {unique: false});
            objectStore.createIndex("messageType","messageType",{
                unique: false,
            });
        };
    });
}

将创建数据库的操作封装成了一个函数,并且该函数返回一个 promise 对象,使得在调用的时候可以链式调用,函数主要接收两个参数: 数据库名称、数据库版本。函数内部主要有三个回调函数,分别是:

  • onsuccess: 数据库打开成功或者创建成功后的回调,这里我们将数据库实例返回了出去。
  • onerror: 数据库打开或创建失败后的回调。
  • onupgradeneeded: 当数据库版本有变化的时候会执行该函数,比如我们想创建新的存储库(表),就可以在该函数里面操作,更新数据库版本即可。

② 插入数据

function addData(db, storeName, data) {
    var request = db
    .transaction([storeName],"readwrite") // 事务对象 指定表格名称和操作模式 ("只读"或"读写")
    .objectStore(storeName) // 仓库对象
    .add(data);

    request.onsuccess = function (event){    
        console.log("数据写入成功");
    };

    request.onerror = function (event) {
        console.log("数据写入失败");
    };
}

 IndexedDB 插入数据需要通过事务来进行操作,插入的方法也很简单,利用 IndexedDB 提供的 add方法即可,这里同样将插入数据的操作封装成了一个函数,接收三个参数,分别如下:

  • db: 在创建或连接数据库时,返回的db实例,需要那个时候保存下来
  • storeName: 仓库名称(或者表名),在创建或连接数据库时就已经创建好了仓库。
  • data: 需要插入的数据,通常是一个对象

 ⭕注意 :  插入的数据是一个对象,而且必须包含声明的索引键值对


③通过主键读取数据 

function getDataByKey(db, storeName, key) {
    return new Promise((resolve, reject) => {
        var transaction = db.transaction([storeName]); // 事务
        var objectstore = transaction.objectstore(storeName); // 仓库对象
        var request = objectstore.get(key); // 通过主键获取数据

        request.onerror = function (event) {
            console.log("事务失败");
        };
    
        request.onsuccess = function (event) {
            console.log("主键查询结果:",,request.result);
            resolve(request.result);
        };
    });
}

④通过游标查询数据

function cursorGetData(db, storeName){
    let list = [];
    var store = db
        .transaction(storeName,"readwrite") // 事务
        .objectstore(storeName); // 仓库对象
    var request = store.openCursor(); // 指针对象
    // 游标开启成功,逐行读数据
    request.onsuccess = function (e) {
        var cursor = e.target.result;
        if (cursor) {
            // 必须要检查
            list.push(cursor.value);
            cursor.continue(); // 遍历了存储对象中的所有内容
        } else {
            console.log("游标读取的数据",list);
        }
    };
}

⑤通过索引查询数据

function getDataByIndex(db,storeName, indexName, indexValue){
    var store = db,transaction(storeName, "readwrite").objectstore(storeName);
    var request = store.index(indexName).get(indexValue);
    request.onerror = function () {
        console.log("事务失败");
    };
    request.onsuccess = function (e) {
        var result = e.target.result;
        console.log("索引查询结果:",result);
    };
}

索引名称 即创建仓库的时候创建的索引名称,也就是键值对中的键,最终会查询出所有满足传入函数索引值的数据。

索引名称即创建仓库的时候创建的索引名称,也就是键值对中的键。最终会查询出仅一条传入函数索引值的数据。


⑥通过索引和游标查询数据

单独通过索引或者游标查询出的数据都是部分或者所有数据,如果想要查询出索引中满足某些条件的所有数据,那么单独使用索引或游标是无法实现的。当然,可以查询出所有数据之后在循环数组筛选出合适的数据,但是这不是最好的实现方式,最好的方式当然是将索引和游标结合起来。

function cursorGetDataByIndex(db,storeName ,indexName ,indexValue ){
    let list = [];
    var store = db.transaction(storeName."readwrite").objectstore(storeName); // 仓库对象
    var request = store
        .index(indexName) // 索引对象
        .openCursor(IDBKeyRange.only(indexValue)); // 指针对象
    request.onsuccess = function (e) {var cursor = e.target.result;
        if (cursor) {
            // 必须要检查
            list.push(cursor.value);
            cursor.continue(); // 遍历了存储对象中的所有内容
        } else {
            console.log("游标索引查询结果:",list);
        }
    };
    request.onerror = function (e) {};
}

⑦通过索引和游标分页查询

IndexedDB 分页查询 不像 MySQL 分页查询那么简单,没有提供现成的API,如 limit 等,所以需要自己实现分页。

function cursorGetDataByIndexAndPage(
    db ,  //数据库实例
    storeName,
    indexName,
    indexValue,
    page,
    pageSize
){
    let list = []; //设置空数组用来保存实例
    let counter = ; // 计数器——停止游标
    let advanced = true; // 是否跳过多少条查询
    var store = db.transaction(storeName, "readwrite"),obiectStore(storeName): // 库对象
    var request = store
        .index(indexName) // 索引对象
        .openCursor(IDBKeyRange.only(indexValue)); // 指针对象
    request.onsuccess = function (e) {
        var cursor = e.target.result;
        if (page > 1 && advanced) {
            advanced = false; //是否跳转
            cursor.advance((page - 1) * pagesize); // 跳过多少条
            return;
        }
        if (cursor) {
                // 必须要检查
                list.push(cursor.value);
                counter++;
                if (counter < pageSize) [
                cursor.continue(); // 遍历了存储对象中的所有内容
            } else {
                cursor = null;
                console.log("分页查询结果",,list);
            }
       } else {
            console.log("分页查询结果",list);
       }
    };    
    request.onerror = function (e) {};
}

IndexedDB的一个APl: advance。该函数可以让游标跳过多少条开始查询。假如额分页是每页10条数据,现在需要查询第2页,那么就需要跳过前面10条数据,从11条数据开始查询,直到计数器等于10,那么就关闭游标,结束查询。


⑧更新数据

IndexedDB更新数据较为简单,直接使用 put 方法,值得注意的是如果数据库中没有该条数据,则会默认增加该条数据,否则更新。喜欢更新和新增都是用put方法,这也是可行的。

function updateDB(db, storeName, data) {
    var request = db
        .transaction([storeName],"readwrite") // 事务对象
        .objectstore(storeName) // 仓库对象
        .put(data);

    request.onsuccess = function () {
        console.log("数据更新成功");
    };

    request.onerror = function () {
        console.log("数据更新失败");
    };
}

 put方法接收一个数据对象


⑨通过主键删除数据

主键即创建数据库时申明的 keyPath,它是唯一的。

function deleteDB(db, storeName, id) {
    var request = db
        .transaction([storeName],"readwrite")
        .objectstore(storeName)
        .delete(id);
    request.onsuccess = function () {
        console.log("数据删除成功");
    };

    request.onerror = function () {
        console.log("数据删除失败");
    };
}

⑩通过索引和游标删除指定数据

有时候拿不到主键值,只能只能通过索引值来删除,通过这种方式,可以删除一条数据(索引值唯一)或者所有满足条件的数据 (索引值不唯一)。

function cursorDelete(db,storeName,indexName,indexValue){
    var store = db,transaction(storeName,"readwrite").objectstore(storeName);
    var request = store
        .index(indexName) // 索引对象
        .openCursor(IDBKeyRange.only(indexValue)); // 指针对象
    request.onsuccess = function (e) {
        var cursor = e.target.result;
        var deleteRequest;
        if (cursor) {
            deleteRequest = cursor.delete(); // 请求删除当前项
            deleteRequest.onerror = function () {
                console.log("游标删除该记录失败");
            };
            deleteRequest.onsuccess = function () {    
                console.log("游标删除该记录成功");
            };
            cursor.continue();
        }
    };
    request.onerror = function (e){ };
}

上段代码可以删除索引值为indexValue的所有数据,值得注意的是使用 IDBKeyRange.only0API,该API代表只能当两个值相等时,具体API解释可参考MDN官网。


⑪关闭数据库

 当数据库操作完毕后,建议关闭它,节约资源。

function closeDB(db) {
    db.close();
    console.log("数据库已关闭");
}

⑫删除数据库

function deleteDBAll(dbName){
    console.log(dbName);
    let deleteRequest = window,indexedDB.deleteDatabase(dbName);
    deleteRequest.onerror = function (event) {
        console.log("删除失败");
    };
    deleteRequest.onsuccess = function (event) {
        console.log("删除成功");
    };
}

总结:

IndexedDB 是 HTML5 标准中定义的一种在浏览器端存储大量结构化数据的 API,它具备以下特点:

  1. 异步 API:IndexedDB 采用异步 API 进行访问和操作,能够更好地应对大量数据存储、高并发数据访问等需求。
  2. 大规模数据存储:IndexedDB 支持存储大量的结构化数据,并支持索引和事务处理等高级操作,适用于需要高性能本地存储大规模数据的场景。
  3. 数据库查询:IndexedDB 支持复杂的查询,包括范围查询和游标查询等,可帮助开发者进行精确查询和高效数据检索。
  4. 数据库设计:IndexedDB 本身是基于 NoSQL 的键值存储数据库,和其他数据库(如 MongoDB)的设计理念相似,能够帮助开发者进行灵活的数据库设计和数据模型设计。

相比于其他的浏览器端存储技术,IndexedDB 具有更好的跨平台兼容性、安全性和扩展性,可以满足现代 Web 应用对于数据存储的各种要求。但是,由于其使用较为复杂,需要开发者深入了解浏览器端存储技术、JavaScript 异步编程、数据库设计和查询等方面才能够充分发挥其优势。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IndexedDB 是浏览器提供的本地数据库,可以在浏览器中存储结构化数据。下面是 IndexedDB 的基本使用方法: 1. 打开数据库 使用 `indexedDB` 对象的 `open()` 方法打开数据库,如下所示: ``` let request = indexedDB.open('myDB', 1); ``` 其中,第一个参数是数据库名称,第二个参数是数据库版本号。如果数据库不存在,则会创建一个新的数据库。 2. 创建对象仓库 在成功打开数据库的回调方法 `request.onsuccess` 中,可以获取到数据库对象 `event.target.result`,然后使用它的 `createObjectStore()` 方法创建一个对象仓库(即数据表),如下所示: ``` let db = event.target.result; let objectStore = db.createObjectStore('people', { keyPath: 'id' }); ``` 其中,第一个参数是对象仓库的名称,第二个参数是一个对象,包含一个 keyPath 属性和其他可选属性。keyPath 用来指定数据表中的主键。 3. 添加数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `add()` 方法向数据表中添加数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.add({ id: 1, name: 'John Doe' }); ``` 其中,第一个参数是一个数组,包含要访问的对象仓库的名称,第二个参数是事务类型,可以是 'readonly' 或 'readwrite'。`add()` 方法的参数是要添加的数据。 4. 查询数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `get()` 方法查询数据,如下所示: ``` let transaction = db.transaction(['people']); let objectStore = transaction.objectStore('people'); let request = objectStore.get(1); request.onsuccess = function(event) { console.log('Name: ' + event.target.result.name); }; ``` `get()` 方法的参数是要查询的数据的主键值。查询结果保存在 `request.onsuccess` 回调方法中的 `event.target.result` 中。 5. 更新数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `put()` 方法更新数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.put({ id: 1, name: 'Jane Doe' }); ``` `put()` 方法的参数是要更新的数据。 6. 删除数据 使用事务 `db.transaction()` 开启一个事务,然后使用 `delete()` 方法删除数据,如下所示: ``` let transaction = db.transaction(['people'], 'readwrite'); let objectStore = transaction.objectStore('people'); let request = objectStore.delete(1); ``` `delete()` 方法的参数是要删除的数据的主键值。 以上就是 IndexedDB 的基本使用方法。需要注意的是,IndexedDB 的 API 非常庞大,不仅仅包含上面提到的这些方法,还包括索引、游标、版本升级等功能。如果需要更详细的介绍和示例代码,可以参考 MDN 的文档:https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值