IndexedDB——在浏览器中使用数据库

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。

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

此特性在 Web Worker 中可用。

如大多数的 web 储存解决方案一样,IndexedDB 也遵守同源策略。因此当你在某个域名下操作储存数据的时候,你不能操作其他域名下的数据。


连接


调用 indexedDB.open() 方法来打开数据库,如果没有数据库就创建一个

window.indexedDB.open(name[, version | options])

  • name:数据库名称
  • version:指定数据库版本,当你想要更改数据库格式(比如增加对象存储,非增加记录),必须指定更高版本,通过 versionchange 来更改
  • options:{version: 4, storage: "temporary"}, 指定版本以及是否要为 IndexedDB 使用永久(默认值)存储的存储值
let request = window.indexedDB.open('test', 1)
复制代码

open 返回一个IDBOpenDBRequest对象——触发与此请求相关的后续事件的请求对象。

连接数据库在一个单独的线程中进行,包括以下几个步骤:

  1. 指定数据库已经存在时间:
  • 等待versionchange操作完成。
  • 如果数据库已删除,那等着删除完成。
  1. 如果已有数据库升级给定的version,中止操作并返回类型为VersionError 的DOMError
  2. 如果已有数据库版本记录给定的version,触发一个versionchange操作。
  3. 如果数据库不存在,创建指定名称的数据库,将版本号设置为给定版本,如果给定版本号,则设置为1,并且没有对象存储。
  4. 创建数据库连接。

如果创建连接成功,则触发 suucess 事件

let request = window.indexedDB.open('test', 1)
request.onsuccess = function (event) {
  console.log(request === event.target)
  console.log('IndexedDB 连接成功');
}
复制代码

event.target 其实就是 open 的返回值,也就是 request,这里最有用的是 request.result属性

1682520214(1).png

所有的异步方法返回一个 request 对象。如果 request 对象成功执行了,结果可以通过 result 属性访问到,并且该 request 对象上会触发 success 事件。如果操作中有错误发生,一个 error 事件会触发,并且会通过 result 属性抛出一个异常。

let request = window.indexedDB.open('test', 1)
request.result
复制代码

在状态未变为 done 之前获取 result 或者连接过程中发生错误会抛出错误

1682520238(1).png

除了 onsuccess 之外还有 onerror 和 onupgradeneeded 事件,分别用于错误回调和初次连接数据库时初始化

request.onerror = function (error) {
  console.log(error);
}
request.onupgradeneeded = function (event) {
  const res = request.result;
  let objectStore;
  if (!res.objectStoreNames.contains('person')) {
    objectStore = res.createObjectStore('person', { keyPath: 'id' });
    objectStore.createIndex('name', 'name')
  }
  console.log('person created');
}
复制代码

createObjectStore 方法用于定义数据库的 schama,这个过程只能在onupgradeneeded 中完成。createObjectStore(storeName, {keypath})定义了表名和主键。

此外还有createIndex用于创建索引列。

1682520274(1).png


概念


在 IndexedDB 中有四个比较重要的概念,了解这些概念有助于我们学习使用 IndexedDB

  • objectStore:IndexedDB没有表的概念,它只有仓库store的概念,大家可以把仓库理解为表即可(后续均用表来代称),即一个store是一张表;
  • index:我们可以在创建store的时候同时创建索引,在后续对store进行查询的时候即可通过索引来筛选,给某个字段添加索引后,在后续插入数据的过成功,索引字段便不能为空;
  • cursor:游标,用于遍历或迭代数据库中的多条记录,游标有一个源,指示需要遍历哪一个索引或者对象存储区。它在所属区间范围内有一个位置,根据记录健(存储字段)的顺序递增或递减方向移动。游标使应用程序能够异步处理在游标范围内的所有记录;
  • transaction:IndexedDB支持事务,即对数据库进行操作时,只要失败了,都会回滚到最初始的状态,确保数据的一致性。


操作


使用 transaction 来创建事务,所有的表操作都必须提前创建事务

transaction(table, mode)

  • table:要连接的表名,是一个数组
  • mode:要创建的事务类型,可选值有readwritereadonly

创建事务之后获通过 objectStore 来获取对象存储实例,获取到实例之后就可以对表进行增删改查的操作了。

objectStore(table)

  • table:表名,需要在创建事务是添加到 tableList 中

add

新增一条表数据,如果新增一个已存在的主键则会被忽略

function add() {
  if (request.readyState === 'done') {
    const db = request.result
    db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .add({ id: 1, name: 'king', age: 18 })
  }
}
复制代码

put

修改表数据

function put() {
  if (request.readyState === 'done') {
    const db = request.result
    db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .put({ id: 1, name: 'king', age: 23 })
  }
}
复制代码

delete

删除一条表数据,删除数据时只需要传入主键的值即可

function del() {
  if (request.readyState === 'done') {
    const db = request.result
    db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .delete(1)
  }
}
复制代码

get

通过主键获取值,这里注意获取值时需要通过回调才能拿到数据,换句话说,只有触发 success 时才能拿到结果,因为操作是异步的

function get() {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .get(1)
    res.onsuccess = e => {
      console.log(res.result);
    }
  }
}
复制代码

除了使用主键查询之外,还可以使用索引查询,会返回符合查询条件的第一条数据

function index() {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .index('name')
      .get('king')
    res.onsuccess = e => {
      console.log(res.result);
    }
  }
}
复制代码

getAll

根据索引查询时除了可以获取一条数据,还可以使用 getAll 来通过索引批量获取数据, getAll 还可以控制查询的数据条数

getAll(query, count)

count 最大支持2^32 - 1,最小支持 0

function getAll() {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .index('name')
      .getAll('king', 2)
    res.onsuccess = e => {
      console.log(res.result);
    }
  }
}
复制代码

cursor

除了上面的两种查询方式,还可已使用游标的方式来进行查询。游标查询可以通过 continue 方法一直顺序遍历知道不再调用 continue。

function cursor() {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .openCursor()
    res.onsuccess = e => {
      const cursor = e.target.result // ===res.result
      if (cursor) {
        console.log(cursor.value);
        cursor.continue()
      }
    }
  }
}
复制代码

游标查询也可使用索引的方式来查询指定的数据集,通过 IDBKeyRange.only(indexValue) 来过滤指定的索引值

function cursorIndex() {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .index('name')
      .openCursor(IDBKeyRange.only('king'))
    res.onsuccess = e => {
      const cursor = e.target.result
      if (cursor) {
        console.log(cursor.value);
        cursor.continue()
      }
    }
  }
}
复制代码

可以利用游标进行更新和删除,直接在cursor 对象上直接调用delete()update(value)即可

分页查询

游标对象提供了一个 advance(count) 方法用于跳过count 个数据,然后配合计数即可完成分页功能

function cursorPage(page, size) {
  if (request.readyState === 'done') {
    const db = request.result
    const res = db.transaction(['person'], 'readwrite')
      .objectStore('person')
      .openCursor()
    let advance = true
    let count = 0
    res.onsuccess = e => {
      const cursor = e.target.result
      if (advance) {
        advance = false
        cursor.advance((page - 1) * 2)
        return
      }
      if (cursor) {
        console.log(cursor.value);
        count++
        if (count < size) {
          cursor.continue()
        }
      }
    }
  }
}
复制代码

同理,该方法可应用于索引+游标查询分页

关闭链接

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

更多方法可以看一下 MDN

相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
6月前
|
存储 监控 安全
360 企业安全浏览器基于阿里云数据库 SelectDB 版内核 Apache Doris 的数据架构升级实践
为了提供更好的日志数据服务,360 企业安全浏览器设计了统一运维管理平台,并引入 Apache Doris 替代了 Elasticsearch,实现日志检索与报表分析架构的统一,同时依赖 Doris 优异性能,聚合分析效率呈数量级提升、存储成本下降 60%....为日志数据的可视化和价值发挥提供了坚实的基础。
360 企业安全浏览器基于阿里云数据库 SelectDB 版内核 Apache Doris 的数据架构升级实践
|
1月前
|
存储 移动开发 大数据
HTML5 Web IndexedDB 数据库详解
IndexedDB 是一种高效的浏览器存储方案,允许在本地存储大量结构化数据,支持索引和事务,适用于需要离线和大数据处理的应用。它由数据库、对象仓库等组成,通过键值对存储数据,确保数据一致性和完整性。本介绍展示了如何创建、读取、更新和删除数据,以及事务和错误处理的最佳实践。
|
1月前
|
Web App开发 SQL 数据库
使用 Python 解析火狐浏览器的 SQLite3 数据库
本文介绍如何使用 Python 解析火狐浏览器的 SQLite3 数据库,包括书签、历史记录和下载记录等。通过安装 Python 和 SQLite3,定位火狐数据库文件路径,编写 Python 脚本连接数据库并执行 SQL 查询,最终输出最近访问的网站历史记录。
|
1月前
|
存储 移动开发 数据库
HTML5 Web IndexedDB 数据库常用数据存储类型
IndexedDB 支持多种数据存储类型,满足复杂数据结构的存储需求。它包括基本数据类型(如 Number、String、Boolean、Date)、对象(简单和嵌套对象)、数组、Blob(用于二进制数据如图像和视频)、ArrayBuffer 和 Typed Arrays(处理二进制数据)、结构化克隆(支持 Map 和 Set 等复杂对象),以及 JSON 数据。尽管不直接支持非序列化数据(如函数和 DOM 节点),但可以通过转换实现存储。开发者应根据具体需求选择合适的数据类型,以优化性能和使用体验。
|
25天前
|
NoSQL 前端开发 MongoDB
前端的全栈之路Meteor篇(三):运行在浏览器端的NoSQL数据库副本-MiniMongo介绍及其前后端数据实时同步示例
MiniMongo 是 Meteor 框架中的客户端数据库组件,模拟了 MongoDB 的核心功能,允许前端开发者使用类似 MongoDB 的 API 进行数据操作。通过 Meteor 的数据同步机制,MiniMongo 与服务器端的 MongoDB 实现实时数据同步,确保数据一致性,支持发布/订阅模型和响应式数据源,适用于实时聊天、项目管理和协作工具等应用场景。
|
4月前
|
SQL 关系型数据库 MySQL
|
4月前
|
存储 JSON JavaScript
数据库操作对象 db,用于与浏览器的 localStorage 交互
数据库操作对象 db,用于与浏览器的 localStorage 交互
41 0
|
存储 SQL NoSQL
浏览器端数据库IndexedDB
1.概念 IndexedDB是一种轻量级NoSQL(Not Only SQL,泛指非关系型)数据库,用来持久化大量客户端数据。
|
前端开发 Java 数据库
欢迎来到Jsp编程课时十二——今天实现的目标是。@1将数据库的数据发送到浏览器。@2利用浏览器实现对数据库的增删改查操作。@3理解MVC三层架构的定义。(三)
欢迎来到Jsp编程课时十二——今天实现的目标是。@1将数据库的数据发送到浏览器。@2利用浏览器实现对数据库的增删改查操作。@3理解MVC三层架构的定义。(三)
102 0
|
前端开发 Java 数据库
欢迎来到Jsp编程课时十二——今天实现的目标是。@1将数据库的数据发送到浏览器。@2利用浏览器实现对数据库的增删改查操作。@3理解MVC三层架构的定义。(二)
欢迎来到Jsp编程课时十二——今天实现的目标是。@1将数据库的数据发送到浏览器。@2利用浏览器实现对数据库的增删改查操作。@3理解MVC三层架构的定义。(二)
66 0