AICon全球人工智能与机器学习技术大会8折特惠,购票立减¥960! 了解详情
写点什么

浏览器里的本地数据库:IndexedDB

2021 年 1 月 29 日

浏览器里的本地数据库:IndexedDB

IndexedDB 是什么


在现代浏览器的本地存储方案中,indexedDB 是一项重要的能力组成, 它是可以在浏览器端使用的本地数据库,可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案 Cookie 或者 LocalStorage 无法提供的能力。单从数据库类型来看,IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。


IndexedDB 的主要概念


IndexedDB 是一个比较复杂的 API 组合,学习它的过程就相当于学习它的各个对象 API 接口,包括以下这些( IDB  指当前操作的数据库实例 ):


  • 数据库:IDBDatabase 对象

  • 仓库对象:IDBObjectStore 对象

  • 索引:IDBIndex 对象

  • 事务:IDBTransaction 对象

  • 操作请求:IDBRequest 对象

  • 指针:IDBCursor 对象

  • 主键:IDBKeyRange 对象


在这些 API 中包含一些主要概念:


  • 数据库:数据库是所有相关数据的基本容器。在同源策略( 协议 + 域名 + 端口 )的前提下,每个域名下可以新建任意多的数据库。IndexedDB 中有版本概念,这就规定了同一时刻下只有一个版本的数据库存在。

  • 对象仓库:对象仓库 ObjectStore 在 IndexedDB 中对应的是 MYSQL 中的表 Table。

  • 数据:对象仓库中记录的是若干条数据,数据只有主键和数据体两个部分,主键不能重复,可以为自增的整数编号或者数据中指定的一个属性。数据体可以是任意数据类型,不限于对象。

  • 索引:为不同的属性建立索引可以加快数据的检索。

  • 事务:数据的 CURD (增删查改) 都要通过事务来完成。


通过简单的对比图来理解 IndexedDB 的概念:



快速起步 IndexedDB


在介绍了 IndexedDB 的主要概念之后,可以通过一个简单实用的 CURD 例子来学习在日常开发中我们是怎么使用 IndexedDB 的,各个 API 细节日后可以慢慢深入学习。


  1. 必不可少的浏览器支持检查:


if('indexedDB'inwindow){  console.log('当前浏览器支持 IndexedDB');  return;} else {  console.log('您的浏览器不支持 IndexedDB')  // todo 建议升级或者更换其他浏览器}
复制代码


  1. 连接数据库


// 数据库实例let db;// 数据库打开操作,第一个参数是数据库名称, 第二个参数是数据库版本let DBRequestLink = window.indexedDB.open('dataBaseName', 1)DBRequestLink.onsuccess = function(event) {  // 获取数据库实例  db = DBRequestLink.result;  // 其他操作};// 这个监听回调触发于数据库首次新建、open数据库时传递新版本(只能比之前传递的版本高)DBRequestLink.onupgradeneeded = function(event) {};
复制代码


  1. 创建数据库的主键和字段


DBOpenRequest.onupgradeneeded = function(event) {  let db = event.target.result;
// 创建一个数据库存储对象,并指定主键 let objectStore = db.createObjectStore('person', { keyPath: 'id', autoIncrement: true });
/* 定义存储对象的数据项 * 第一个参数是创建的索引名称,可以为空 * 第二个参数是索引使用的关键名称,可以为空 * 第三个参数是可选配置参数,可以不传,常用参数之一就是 unique ,表示该字段是否唯一,不能重复 */ objectStore.createIndex('id', 'id', { unique: true }); objectStore.createIndex('name', 'name'); objectStore.createIndex('age', 'age'); objectStore.createIndex('sex', 'sex');};
复制代码


在上述操作中,我们先定义了上文中提到的 IDBObjectStore 对象,并指定主键为 id ,随后又通过 createIndex 来创建字段。值得注意的是虽然创建了四个字段,但在 IndexedDb 中数据还是分为主键 id 和数据主体两个部分,并不会像 MYSQL 中在 Table 中呈现四列。


  1. 向数据库中添加数据


// 这里的 db 就是第二步中的 db 对象,// transaction api 的第一个参数是数据库名称,第二个参数是操作类型let newItem = {  id: 1,  name: '徐嘻嘻',  age: 3,  sex: 'female'};let transaction = db.transaction('dataBaseName', "readwrite");// 找到对应的存储对象let objectStore = transaction.objectStore('person');// 添加到数据对象中, 传入javascript对象objectStore.add(newItem);
复制代码


新建操作是在新建了一个 事务( IDBTransaction 对象)的前提下完成的,传入的数据不需要做任何转换,可以无缝传入 Javascript 对象。


  1. 修改数据库中的数据


// 这里的 db 就是第二步中的 db 对象,// 新建事务let transaction = db.transaction('dataBaseName', "readwrite");// 新数据主体let newRecord = {  id: 1,  name: '徐嘎嘎',  age: 5,  sex: 'male'};// 打开已经存储的数据对象let objectStore = transaction.objectStore('person');// 获取存储的对应键的存储对象, 传入主键 id,值为 1let objectStoreRequest = objectStore.get(1);// 获取成功后替换当前数据objectStoreRequest.onsuccess = function(event) {  // 数据  var record = objectStoreRequest.result;  // 遍历替换  for (let key in newRecord) {    if (typeof record[key] != 'undefined' || key !== 'id') {      record[key] = newRecord[key];    }  }  // 更新数据库存储数据  objectStore.put(record);};
复制代码


基本思路是创建一个事务,先找到想要修改的数据主体,然后在更新该数据主体内容。事务创建逻辑相同,并在创建之后调用事务的 get 和 put 操作。


  1. 删除数据库中的数据


// 这里的 db 就是第二步中的 db 对象,// 新建事务let transaction = db.transaction('dataBaseName', "readwrite");// 打开已经存储的数据对象let objectStore = transaction.objectStore('person');// 获取存储的对应键的存储对象, 传入主键 id,值为 1let objectStoreRequest = objectStore.delete(1);
复制代码


  1. 调用 delete 接口,传入指定的 id 即可。


可以提效的类库


从上面的例子中可以看出,每一次操作需要至少三行代码才能完成,而且需要一直维护 DB 的对象引用,避免它被回收,这样子开发代码膨胀得太厉害,所以我们在业务中引入其他类库来减少代码量


  • LocalForage

  • 可以指定数据存储方案,默认依次为 IndexedDB、WebSQL、LocalStorage,意味着当前 IndexedDB 失效可以有兜底措施。

  • API 简化为 CRUD ( getItem、removeItem、setItem、clear )

  • 库大小为 475b

  • Pouchdb

  • API 简化为 put、get、remove,基于 promise 来检查回收错误

  • 有较好的错误日志机制, 如失败,冲突等等,方便调试

  • 库大小为 255b


这两个类库比较符合我们的开发要求,我们当前使用的是 LocalForage。


结束语


在业务开发中,我们都会碰到或多或少的本地存储需求,本文介绍了其中一种存储方案 IndexedDB 的简单实践。就我们的应用场景来看,IndexedDB 的适用面还是很广的。考虑到 IE10 也可以支持,把它实践在实际项目中应该是没有问题的。


头图:Unsplash

作者:麦田

原文:https://mp.weixin.qq.com/s/yNF4eQyETmSBoDJJT2m-yA

原文:浏览器里的本地数据库:IndexedDB

来源:政采云前端团队 - 微信公众号 [ID:Zoo-Team]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021 年 1 月 29 日 22:372368

评论 2 条评论

发布
用户头像
这种文章有任何价值吗?
2021 年 02 月 07 日 01:09
回复
用户头像
InfoQ跟政采云有合作么?什么文章都上,文章也不勘误。。。
2021 年 01 月 30 日 01:54
回复
没有更多了
发现更多内容

Athena雅典娜交易所系统开发|Athena雅典娜交易所软件APP开发

开發I852946OIIO

系统开发

BAT等大厂面试复习资料文档整理:ActiveMQ+redis+Spring+高并发多线程+JVM

Java架构之路

Java 程序员 架构 面试 编程语言

探营苏州数字人民币试点

CECBC区块链专委会

数字人民币

破51项国际榜单纪录!解读华为云擎天架构调度求解引擎

华为云开发者社区

华为 架构 华为云

XMEX交易所系统软件开发|XMEX交易所APP开发

开發I852946OIIO

系统开发

网络入门模拟器:Cisco Packet Tracer 实验教程

即构SDK12月迭代:新增多项质量回调,互动白板、云录制SDK同步更新

ZEGO即构

网易云音乐Java面试题:Mybatis事务+SpringBean+Java锁+Redis

Crud的程序员

Java redis spring 程序员 面试

如何在软件发布计划中自动化语义化版本与变更日志

华为云开发者社区

自动化 工具 发布

阿里三面惨遭被虐,spring,jvm,mybatis,并发编程等一窍不通

Java架构之路

Java 程序员 架构 面试 编程语言

SSO的通用标准OpenID Connect

程序那些事

OAuth 2.0 程序那些事 授权框架 安全框架 openid

工作日志:一文总结HBase从搭建到实操,大家一起进步

小Q

大数据 学习 编程 面试 HBase

海淀区政府携手百度,打造数字政务时代新门户

DT极客

有了Git这个功能,再也不需要依赖IDE了!

云流

编程 架构

C语言服务器编程必备常识

MySQL从删库到跑路

c

腾讯云TcaplusDB成为首批通过信通院-键值型内存数据库功能评测的产品,树立内存数据库行业标杆

TcaplusDB

数据库 nosql 腾讯云 腾讯 国产化

基于LiteOS Studio零成本学习LiteOS物联网操作系统

华为云开发者社区

操作系统 物联网 华为云

盘点 2020 | 坚持写技术博客一年能有多少收获!

小傅哥

Java 小傅哥 技术人 盘点2020

LeetCode题解:429. N叉树的层序遍历,BFS,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

手把手教你免费获取正版 Jetbrains 全家桶 License

郭旭东

ide JetBrains

我叫你不要重试,你非得重试。这下玩坏了吧?

比伯

Java 编程 架构 面试 程序人生

一个改变世界的“箱子”

阿里巴巴云原生

Docker 阿里云 容器 云原生 k8s

终于学完了阿里云大数据架构师推荐的Flink入门与实战PDF

小Q

大数据 flink 学习 编程 面试

SpringBoot魔法堂:应用热部署实践与原理浅析

云流

设计原则 框架 spring Boot Starter

BATJ面试常被问到的100+题:Spring+微服务+SpringMVC+MyBatis

Java架构之路

Java 程序员 架构 面试 编程语言

你只修改了2行代码,为什么需要两天时间?

Java架构师迁哥

赶紧看!阿里架构师必备“绝杀版”Tomact架构笔记堪称绝技

比伯

Java tomcat 编程 架构 程序人生

互联网新规鼓励保险与大数据、区块链等新技术融合!业内呼吁配套产品管理制度尽快出炉

CECBC区块链专委会

互联网金融

聚焦LS-MIMO的四大层面,浅谈5G关键技术

华为云开发者社区

华为 5G 华为云

没弄懂这些Java基础,简历上千万别写熟悉:异常+反射+注解+泛型

小Q

Java 学习 编程 面试 基础

第三代人工智能基础设施背后,是一次技术应用的常识普及运动

脑极体

浏览器里的本地数据库:IndexedDB-InfoQ