1、indexedDB 是什么?
IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。
其简单而言,IndexedDB 就是一个基于事务操作的key-value型数前端数据库,其API大多是异步的。
事务:事务是数据库中的一组操作,它们要么全部成功完成,要么全部失败,以确保数据库的一致性和可靠性。事务型数据库主要用于记录和管理各种业务交易和操作,如订单处理、库存管理、银行交易、在线购物等等
一个栗子:
"要么全部成功要么全部失败" 是事务的核心特性之一,称为事务的原子性(Atomicity)。这意味着在事务中的一组操作要么全部成功执行,要么如果有任何一个操作失败,那么整个事务都会被回滚到初始状态,不会产生部分执行的结果。
让我用一个简单的示例来解释这个概念:
假设你正在管理一个银行账户的数据库,其中有两个相关的操作:转账和更新余额。这两个操作必须作为一个事务来执行,以确保数据的一致性。
转账操作:从一个账户A向另一个账户B转账100美元。
更新余额操作:更新账户A和账户B的余额。
现在,如果这两个操作不作为一个事务,可能会发生以下问题:
如果在转账后发生故障,但在更新余额之前,那么资金将丢失,因为A账户已经减少了100美元,但B账户没有收到相应的增加。
如果在更新余额后发生故障,但在转账之前,那么A和B账户都会显示不正确的余额。
为了解决这个问题,你可以将这两个操作放在一个事务中:
开始事务。
执行转账操作:从A账户减去100美元,向B账户增加100美元。
执行更新余额操作:更新A和B账户的余额。
提交事务。
现在,如果在执行任何一个步骤中发生故障,整个事务将被回滚到初始状态,即A和B账户的余额都不会发生变化。这确保了要么全部成功(转账和余额更新都成功),要么全部失败(任何一个步骤失败)的原子性特性。这种方式可以保持银行账户数据的一致性和可靠性。
特点:
-
键值对储存 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
-
异步 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
-
支持事务 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
-
同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
-
支持二进制储存 IndexedDB 不仅可以储存字符串,还可以储存二进制数据 ArrayBuffer 对象和 Blob 对象。
-
储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
2、前端本地化存储方式对比
特性 | cookie | localStorage | sessionStorage | indexedDB |
---|---|---|---|---|
数据生命周期 | 一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成 | 除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器 | 页面关闭就清理刷新依然存在,不支持跨页面交互 | 除非被清理,否则一直存在 |
数据存储大小 | 4K | 5M | 5M | 不限制大小 |
与服务端通信 | 每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题 | 不参与 | 不参与 | 不参与 |
特点 | 字符串键值对在本地存储数据 | 字符串键值对在本地存储数据 | 字符串键值对在本地存储数据 | IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。 |
indexedDB支持情况:浏览器支持良好
3、核心概念
数据库:IDBDatabase 对象,数据库有版本概念,同一时刻只能有一个版本,每个域名可以建多个数据库
对象仓库:IDBObjectStore 对象,类似于关系型数据库的表格
索引: IDBIndex 对象,可以在对象仓库中,为不同的属性建立索引,主键建立默认索引
事务: IDBTransaction 对象,增删改查都需要通过事务来完成,事务对象提供了error、abord、***plete三个回调方法,监听操作结果
4、怎么用
1.创建或打开数据库
mounted() {
const self = this;
/*第一个参数:数据库名称,第二个参数:版本号*/
this.indexedDB = window.indexedDB.open('test', 1);
/*监听打开状态*/
this.indexedDB.onsu***ess = function (e) {
console.log('数据库打开成功', e);
self.db = e.target.result;
};
this.indexedDB.onerror = function (e) {
console.log('数据库打开报错');
};
/*第一次就会触发*/
this.indexedDB.onupgradeneeded = function (e) {
console.log('数据库升级成功');
self.db = e.target.result;
/*判断是否存在user这个store*/
if (!self.db.objectStoreNames.contains('user')) {
const objectStore = self.db.createObjectStore('user', { keyPath: 'email' });
// 在这里创建索引
objectStore.createIndex('indexId', 'id', { unique: true });
}
};
},
2.添加操作 :这些操作都是默认依赖于主键的
add() {
//transaction 方法用于创建一个事务, 第一个参数是一个数组,包含了你想要在事务中操作的对象存储的名称,第二个参数是字符串,表示事务的类型
const transaction = this.db.transaction(['user'], 'readwrite');
//一旦事务创建成功,我们可以使用 .objectStore() 方法从事务中获取一个指定的对象存储
const store = transaction.objectStore('user');
const request = store.add({id: 2, name: '张三', age: 24, email: '123@.***'});
request.onsu***ess = function (e) {
console.log('数据写入成功');
};
request.onerror = function (e) {
console.log('数据写入失败:', e);
};
},
3.修改操作
update() {
const transaction = this.db.transaction(['user'], 'readwrite');
const store = transaction.objectStore('user');
const request = store.put({id: 3, name: '李四1', age: 24, email: '1235@.***'});
request.onsu***ess = function (e) {
console.log('数据更新成功');
};
request.onerror = function (e) {
console.log('数据更新失败:', e);
};
},
4.获取操作
get() {
const transaction = this.db.transaction(['user'], 'readwrite');
const store = transaction.objectStore('user');
const request = store.get('123@.***');
request.onsu***ess = function (e) {
console.log('数据获取成功', e.target.result);
};
request.onerror = function (e) {
console.log('数据获取失败:', e);
};
},
5.删除操作
handleDelete() {
const transaction = this.db.transaction(['user'], 'readwrite');
const store = transaction.objectStore('user');
const request = store.delete('123@.***');
request.onsu***ess = function (e) {
console.log('数据删除成功');
};
request.onerror = function (e) {
console.log('数据删除失败:', e);
};
},
6.索引
indexGet() {
const transaction = this.db.transaction(['user'], 'readwrite');
const store = transaction.objectStore('user');
const index = store.index('indexId');
const request = index.get(3);
request.onsu***ess = function (e) {
console.log('数据获取成功', e.target.result);
};
request.onerror = function (e) {
console.log('数据获取失败:', e);
};
},
索引的意义:索引在IndexedDB中具有重要作用,它们用于提高数据检索和查询的性能
索引的实现原理:(b+树)
https://pic4.zhimg.***/80/v2-87fd4faf38729f791003085eaa7464bb_1440w.webp
5.有什么用
离线日志
在线编辑工具(ps,可视化平台)返回上一步
接口数据缓存
等等
6.比较成熟的三方库
localforage