浏览器数据库 IndexedDB

随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。

现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。

  • IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。
  • IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。

关系型数据库和非关系型数据库

关系型数据库:对一致性要求非常严格,例如要写入100个数据,前99个成功了,结果第100个不合法,此时事务会回滚到最初状态。这样保证事务结束和开始时候的存储数据处于一致状态。非常适合银行这种对数据一致性要求非常高的场景。但是,这种一致性保证是牺牲了一部分性能的。

非关系型数据库:不保证一致性但性能更优;数据结构不固定,非常容易扩展。

对比:,“关系型数据库”稳重持久,“非关系型数据库”迅速灵动。在前端领域,Web SQL Database是“关系型数据库”,indexedDB是“非关系型数据库”。

IndexedDB 具有以下特点

  1. 键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
  2. 异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
  3. 支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。 每次操作数据库都必须创建一个事务,2个参数(表名,是否可读写) db.transaction(storeName, ‘readwrite’)
  4. 同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
  5. 储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
  6. 支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

数据库中的事务-transaction

数据库的事务(英文为’transaction’),我们可以理解为对数据库的操作,而且专指一个序列上的操作。举个例子,银行转账,一个账号钱少了然后另一个账号钱多了,这两个操作要么都执行,要么都不执行。像这种操作就可以看成一个事务。事务的提出主要是为了保证并发情况下保持数据一致性。

关系型数据库中的事务具有下面4个基本特征

  1. 原子性(Atomicity):事务中的所有操作作为一个整体提交或回滚。
  2. 一致性(Consistemcy):事物完成时,数据必须是一致的,以保证数据的无损。
  3. 隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的。
  4. 持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留。

IndexedDB 基本概念

IndexedDB API

  • 数据库:IDBDatabase 对象
  • 对象仓库:IDBObjectStore 对象
  • 索引: IDBIndex 对象
  • 事务: IDBTransaction 对象
  • 操作请求:IDBRequest 对象
  • 指针: IDBCursor 对象
  • 主键集合:IDBKeyRange 对象

数据库

数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。

IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。

对象仓库

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

数据记录

对象仓库保存的是数据记录。每条记录类似于关系型数据库的行,但是只有主键和数据体两部分。主键用来建立默认的索引,必须是不同的,否则会报错。主键可以是数据记录里面的一个属性,也可以指定为一个递增的整数编号。

{ id: 1, text: 'foo' }

上面的对象中,id属性可以当作主键。数据体可以是任意数据类型,不限于对象。

索引

为了加速数据的检索,可以在对象仓库里面,为不同的属性建立索引。

事务

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

indexedDb 数据库创建

1、判断兼容性

var indexedDB =window.indexedDB ||window.webkitIndexedDB ||window.mozIndexedDB || window.msIndexedDB;
if (!indexedDB) {console.log('你的浏览器不支持IndexedDB');
}

1、打开数据库

使用 IndexedDB 的第一步是打开数据库,使用indexedDB.open()方法

var request = window.indexedDB.open(databaseName, version);

这个方法接受两个参数,第一个参数是字符串,表示数据库的名字。如果指定的数据库不存在,就会新建数据库。第二个参数是整数,表示数据库的版本。如果省略,打开已有数据库时,默认为当前版本;新建数据库时,默认为1。

indexedDB.open()方法返回一个 IDBRequest 对象。这个对象通过三种事件error、success、upgradeneeded,处理打开数据库的操作结果。

request.onsuccess = function (event) {console.log('打开数据库成功');};request.onerror = function (event) {console.log('打开数据库失败');}

open方法并不会返回一个DB对象,而是返回了一个IDBOpenDBRequest对象,我们通常用到的的DB对象在result属性中:

除了result之外,还有其他的一些属性:

  • onerror: 请求失败的回调函数句柄
  • onsuccess:请求成功的回调函数句柄
  • onupgradeneeded:请求数据库版本变化句柄,当数据版本和数据库当前版本号不一致时就会调用,但是当传入的数据库版本低于数据库的版本号时将会报错,也就是调用onerror

2 新建数据库、对象仓库

新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于,后续的操作主要在upgradeneeded事件的监听函数里面完成,因为这时版本从无到有,所以会触发这个事件。数据初始化回调函数 早于 创建的成功回调。

通常,新建数据库以后,第一件事是新建对象仓库(即新建表)。

request.onupgradeneeded = function(event) {db = event.target.result;var objectStore = db.createObjectStore('person', { keyPath: 'id' });
}

上面代码中,数据库新建成功以后,新增一张叫做person的表格,主键是id。

更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。

request.onupgradeneeded = function (event) {db = event.target.result;var objectStore;if (!db.objectStoreNames.contains('person')) {objectStore = db.createObjectStore('person', { keyPath: 'id' });}
}

主键(key)是默认建立索引的属性。比如,数据记录是{ id: 1, name: '张三' },那么id属性可以作为主键。主键也可以指定为下一层对象的属性,比如{ foo: { bar: 'baz' } }的foo.bar也可以指定为主键。

如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键。

var objectStore = db.createObjectStore('person',{ autoIncrement: true }
);

上面代码中,指定主键为一个递增的整数。

3、 新增索引

新建对象仓库以后,下一步可以新建索引。

request.onupgradeneeded = function(event) {db = event.target.result;var objectStore = db.createObjectStore('person', { keyPath: 'id' });objectStore.createIndex('name', 'name', { unique: false });objectStore.createIndex('email', 'email', { unique: true });
}

上面代码中,IDBObject.createIndex()的三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)。

4、 新增数据

新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。

function add() {var request = db.transaction(['person'], 'readwrite').objectStore('person').add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });request.onsuccess = function (event) {console.log('数据写入成功');};request.onerror = function (event) {console.log('数据写入失败');}
}
add();

上面代码中,写入数据需要新建一个事务。新建时必须指定表格名称和操作模式("只读"或"读写")。新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。

写入操作是一个异步操作,通过监听连接对象的success事件和error事件,了解是否写入成功。

5、 读取数据

读取数据也是通过事务完成。

function read() {var transaction = db.transaction(['person']);var objectStore = transaction.objectStore('person');var request = objectStore.get(1);request.onerror = function(event) {console.log('事务失败');};request.onsuccess = function( event) {if (request.result) {console.log('Name: ' + request.result.name);console.log('Age: ' + request.result.age);console.log('Email: ' + request.result.email);} else {console.log('未获得数据记录');}};
}
read();

上面代码中,objectStore.get()方法用于读取数据,参数是主键的值

6、 遍历数据

遍历数据表格的所有记录,要使用指针对象 IDBCursor。

function readAll() {var objectStore = db.transaction('person').objectStore('person');objectStore.openCursor().onsuccess = function (event) {var cursor = event.target.result;if (cursor) {console.log('Id: ' + cursor.key);console.log('Name: ' + cursor.value.name);console.log('Age: ' + cursor.value.age);console.log('Email: ' + cursor.value.email);cursor.continue();} else {console.log('没有更多数据了!');}};
}
readAll();

上面代码中,新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。

7、 更新数据

更新数据要使用IDBObject.put()方法。

function update() {var request = db.transaction(['person'], 'readwrite').objectStore('person').put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });request.onsuccess = function (event) {console.log('数据更新成功');};request.onerror = function (event) {console.log('数据更新失败');}
}
update();

上面代码中,put()方法自动更新了主键为1的记录。

8、 删除数据

IDBObjectStore.delete()方法用于删除记录。

function remove() {var request = db.transaction(['person'], 'readwrite').objectStore('person').delete(1);request.onsuccess = function (event) {console.log('数据删除成功');};
}
remove();

9、 使用索引

索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。

假定新建表格的时候,对name字段建立了索引。

objectStore.createIndex('name', 'name', { unique: false });

现在,就可以从name找到对应的数据记录了。

var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('李四');
request.onsuccess = function (e) {var result = e.target.result;if (result) {// ...} else {// ...}
}

浏览器数据库 IndexedDB相关推荐

  1. 一行代码,搞定浏览器数据库 IndexedDB

    作者 | 星尘starx 来源 | https://juejin.cn/post/6918705632757415950 前言 2021 年,如果你的前端应用,需要在浏览器上保存数据,有三个主流方案可 ...

  2. indexed true mysql_一行代码,搞定浏览器数据库 IndexedDB

    前言 2021 年,如果你的前端应用,需要在浏览器上保存数据,有三个主流方案可以选择: Cookie:上古时代就已存在,但能应用的业务场景非常有限 LocalStorage:使用简单灵活,但是容量只有 ...

  3. 浏览器数据库IndexedDB

    概述 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据. Cookie 的大小不超过4KB,且每次请求都会发送回服务器: Lo ...

  4. 浏览器数据库IndexedDB介绍

    摘要 在移动端H5页面开发的时候,为了更好的提高用户体验,可以对不常变化的数据做浏览器端数据缓存,在用户打开页面的时候,首先加载本地的数据,然后异步请求服务端,更新数据.在移动端webview中,可以 ...

  5. 浏览器数据库 IndexedDB(一) 概述

    IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作. 背景 随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获 ...

  6. 浏览器数据库 IndexedDB 介绍

    在讲IndexedDB之前,先简单说说cookie.localStorage.sessionStorage. cookie Cookie 的大小不超过4KB,且每次请求都会发送回服务器. localS ...

  7. 浏览器数据库IndexedDB初体验

    最近在项目中尝试使用了一下IndexedDB,这篇仅仅是记录一下IndexedDB简单使用,详情可以查看 阮大神的文章. 业务场景:用户与其他人的聊天数据,我们用的是环信,没有使用环信历史消息API, ...

  8. 前端数据库indexedDB入门

    什么是indexDB 学习文档: 阮一峰老师的分享文档:浏览器数据库 IndexedDB 入门教程 - 阮一峰的网络日志 官方API文档,纯英文,不过提供的代码很有用:Indexed Database ...

  9. 前端三种本地存储方式+indexedDB浏览器数据库存储

    1.cookie存储: 特征:1.不同的浏览器存放的cookie位置不一样,也是不能通用的.2.cookie的存储是以域名形式进行区分的,不同的域下存储的cookie是独立的.3.我们可以设置cook ...

最新文章

  1. [windows server 2008 站点系列五]一招加速域用戶的文件查找速度
  2. Android SDK Tools Setup 提示 “ java se development kit not found”
  3. OpenGL 实例化 Instancing
  4. android百分比扩展枯,Android 增强版百分比布局库 为了适配而扩展
  5. 【Oracle】查看死锁与解除死锁
  6. 【朝夕技术专刊】Core3.1WebApi_Filter-Authorize详解
  7. 如何在CLI命令行下运行PHP脚本,同时向PHP脚本传递参数?
  8. 怎样写一篇优秀论文?看完受益匪浅!
  9. 在线可视化python网站_Python的可视化工具概述
  10. linux wifi开发书籍,Android WIFI开发介绍.pdf
  11. JavaScript清空数组的三种方法
  12. 企业者的福音之8266接入阿里智能,点亮一盏灯
  13. MEF体验使用接口导出的优越性
  14. 【论文】最新自然语言处理领域顶会论文大合集!
  15. 安徽省月度降水量分布数据
  16. 微信小程序canvas 图片绘制
  17. BACKPROPAGATION 手工求解
  18. 通过高德开放平台用出租车数据找出乘客上下车最频繁区域
  19. 解决串口数据接收,实际值FF,接收却是FFFFFFFF
  20. 免费的modelsim安装教程(Intel modelsim altera 的初学者)

热门文章

  1. 如何通过 AirPlay 镜像您的 Mac 显示器
  2. android开发笔记之锁屏界面未读短信未接来电提醒(android 4.4)
  3. Sping的基础知识总结(01)
  4. 基于esp32-cam毕设设计兼日志(1)
  5. zData与持续优化 云和恩墨以创新获天安人寿供应商突出贡献奖
  6. SAS:数据合并简介
  7. 学习笔记整理:Photoshop软件应用-图层的应用和渐变工具
  8. Linux系统:SSH无密登录配置
  9. Ubuntu18.04 截图神器 flameshot
  10. 考驾照自我总结(待更新修正)