indexedDB存储

news2024/12/27 12:29:32

一、概述

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

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

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

IndexedDB 具有以下特点。

(1)键值对储存。 IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。

(2)异步。 IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。

(3)支持事务。 IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。

(4)同源限制 IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。

(5)储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。

(6)支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。

二、基本概念

IndexedDB 是一个比较复杂的 API,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API,就是学习它的各种对象接口。

下面是一些主要的概念。

(1)数据库

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

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

(2)对象仓库

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

(3)数据记录

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

{ id:1, text: 'foo' }

上面的对象中,id属性可以当作主键。

数据体可以是任意数据类型,不限于对象。

(4)索引

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

(5)事务

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

三、操作流程简单示例

IndexedDB 数据库的各种操作,一般是按照下面的流程进行的。这个部分只给出简单的代码示例,用于快速上手,详细的各个对象的 API 请看 这里。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>indexedDB(浏览器本地存储数据库)</title>
  </head>
  <body>
    <p>IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。</p>
    <p>IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。</p>
    <h3>indexedDB特点</h3>
    <ol>
      <li>键值对存储:采用对象仓库存储数据,所有的数据类型都可以直接存入,主键是独一无二的</li>
      <li>异步:</li>
      <li>
        支持事务:IndexedDB
        支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
      </li>
      <li>
        同源限制: IndexedDB
        受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
      </li>
    </ol>
    <script>
      /**
       * databaseName:字符串,表示数据库的名字,不存在则新建
       * version :第二个参数是整数,表示数据库的版本。默认为1
       * 返回一个 IDBRequest 对象 对象通过三种事件error、success、upgradeneeded
       *
       * 新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于,后续的操作主要在upgradeneeded事件的监听函数里面完成
       *
       * 新建数据步骤:
       * step1:新建对象仓库(即新建表
       * step2:新建索引
       *
       * */
      //IDBDatabase对象
      let db;
      //创建或者打开
      let request = window.indexedDB.open('newIDB');
      //删除数据库
      var DBDeleteRequest = window.indexedDB.deleteDatabase('newIDB');

      DBDeleteRequest.onerror = function (event) {
        console.log('Error');
      };

      DBDeleteRequest.onsuccess = function (event) {
        console.log('success');
      };

      //error事件--表示打开数据失败
      request.onerror = function (event) {
        console.log('数据库打开报错');
        db.close();
      };
      request.success = function (event) {
        //通过request对象的result属性拿到数据库对象
        db = request.result;
        console.log(db);
        console.log('数据库打开成功');
      };
      console.log(request);

      //onupgradeneeded---如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件
      request.onupgradeneeded = function (event) {
        //通过事件对象的target.result属性,拿到数据库实例。
        console.log(event);
        //request对象的result属性上面,拿到一个IDBDatabase对象,它表示连接的数据库
        db = event.target.result;

        let objectStore;
        // 更好的写发是判断表是否存在
        if (!db.objectStoreNames.contains('newIDB')) {
          /**新建数据
           * 新建对象仓库(即新建表)
           * 新增一张叫做person的表格,主键是id
           * */
          //主键(key)是默认建立索引的属性。如果没有可以让 IndexedDB 自动生成主键db.createObjectStore('person',{ autoIncrement: true })
          objectStore = db.createObjectStore('newIDB', { keyPath: 'id' });
          /**
           * 新建索引
           * 三个参数分别为索引名称、索引所在的属性、配置对象(说明该属性是否包含重复的值)
           * **/
          objectStore.createIndex('name', 'name', { unique: false });
          objectStore.createIndex('email', 'email', { unique: true });
        }
      };

      /**
       * 新增数据
       * 新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。
       * 写入数据需要新建一个事务
       * 新建时必须指定表格名称和操作模式("只读"或"读写")
       * 写入操作是一个异步操作,通过监听连接对象的success事件和error事件,了解是否写入成功。
       * **/
      function add() {
        //通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。
        var request = db
          .transaction(['newIDB'], 'readwrite')
          .objectStore('newIDB')
          .add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });
        request.onsuccess = function (event) {
          console.log('数据写入成功');
        };

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

      setTimeout(function () {
        console.log(db);
        add();
      }, 2000);

      /** 
       * 读取数据
       * 读取数据也是通过事务完成。
       * **/
      function read() {
        //创建是务
        let transaction = db.transaction(['newIDB']);
        //拿到 IDBObjectStore 对象
        let objectStore = transaction.objectStore('newIDB');
        //objectStore.get()方法用于读取数据,参数是主键的值。
        let request = objectStore.get(1);
        //失败监听
        request.onerror = function (event) {
          console.log('事务失败');
          db.close();
        };
        //成功监听
        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('未获得数据记录');
          }
        };
      }

      setTimeout(function () {
        read();
      }, 4000);

      /**遍历数据
       *遍历数据表格的所有记录,要使用指针对象 IDBCursor。
       *
       * */
      function readAll() {
        let objectStore = db.transaction('newIDB').objectStore('newIDB');
        //新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。
        objectStore.openCursor().onsuccess = function (event) {
          let 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('没有更多数据了!');
          }
        };
      }

      setTimeout(function () {
        readAll();
      }, 6000);

      /**
       * 更新数据
       * 更新数据要使用IDBObject.put()方法。
       * */
      function update() {
        //put()方法自动更新了主键为1的记录。
        let request = db
          .transaction(['newIDB'], 'readwrite')
          .objectStore('newIDB')
          .put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });

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

        request.onerror = function (event) {
          console.log('数据更新失败');
          db.close();
        };
      }

      setTimeout(function () {
        update();
      }, 8000);

      /**
       * 删除数据
       * DBObjectStore.delete()方法用于删除记录
       * **/
      function remove() {
        let request = db.transaction(['newIDB'], 'readwrite').objectStore('newIDB').delete(1);
        request.onsuccess = function (event) {
          console.log('数据删除成功');
        };
      }

      // remove();

      /**
       * 使用索引
       * 索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
       * 
       * 假定新建表格的时候,对name字段建立了索引。
       * objectStore.createIndex('name', 'name', { unique: false });
       * 现在,就可以从name找到对应的数据记录了。
       * */
      function search() {
        let request = db
          .transaction(['newIDB'], 'readonly')
          .objectStore('newIDB')
          .index('name')
          .get('李四');
        request.onsuccess = function (e) {
          var result = e.target.result;
          if (result) {
            console.log('搜索成功');
          } else {
            console.log('搜索失败');
          }
        };
      }

      // search();
    </script>
  </body>
</html>

**注意:使用的时候链接数据库,失败或者完成其他操作关闭数据库;**

 详细的各个对象的 API 请看 这里。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

rocketmq 笔记

cap理论 Consistency&#xff08;一致性&#xff09;Availability&#xff08;可用性&#xff09;Partition tolerance&#xff08;分区容忍性&#xff09; ①一致性&#xff1a;对于客户端的每次读操作&#xff0c;要么读到的是最新的数据&#xff0c;要么读取失败。换句话说…

ElasticSearch -- Prometheus+Grafana监控

向导介绍部署Prometheus配置Grafana下载仪表盘导入仪表盘报警核心指标集群健康和节点可用性主机级别的系统和网络指标JVM内存和垃圾回收搜索和索引性能资源饱和度注册自动重启介绍 Prometheus官方提供了ES的exporter&#xff1a;EsExporter Github地址&#xff1a;elasticsea…

【Vue】Vue不同版本的基本使用

一、Vue的版本 1. Vue1.x几乎被淘汰&#xff0c;不再建议学习与使用。2. Vue2.x<scriptsrc"" target"_blank">https://cdn.jsdelivr.net/npm/vue2.6.14"></script>3. Vue3.x<scriptsrc"" target"_blank">ht…

【IO异常】HTTP请求报错Error writing to server

报错信息如下&#xff1a; [2023-01-04 13:36:02.185]-ERROR-[biz:aplus-task-oms1060189862335877121][sys:aplus-cms-tran1060189866052390912][com.phfund.aplus.cms.tran.module.counter.service.impl.OcrServiceImpl-102][调用远程服务发送文件异常:] cn.hutool.http.Http…

一、HTML5

文章目录一、HTML5二、html5的基本结构三、基本标签四、HTML常用标记4.1 文本标题(h1-h6)4.2 段落文本p4.4 空格4.5 换行 br4.6 水平线4.7 加粗标记4.8 倾斜4.9 扩展4.10 列表4.10.1 ul 无序列表4.10.2 ol 有序列表4.10.3 dl 自定义列表五、块级标签、行级标签一、HTML5 H5是H…

洛谷 P1886 滑动窗口 /【模板】单调队列

滑动窗口 /【模板】单调队列 题目描述 有一个长为 nnn 的序列 aaa&#xff0c;以及一个大小为 kkk 的窗口。现在这个从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最大值和最小值。 例如&#xff1a; The array is [1,3,−1,−3,5,3,…

辨别三星内存条的真假

目录前言一、三星内存为什么水深&#xff1f;二、通过物理手段辨别1.包装2.日期3.是否透光4.颜色5.电阻颜色6.颗粒丝印&#xff08;重点&#xff09;7.其他标签或字迹结语前言 本文截止2023.2.2&#xff0c;针对笔记本内存条 省流&#xff1a;直接JD自营 最近随手在tb买了条三星…

快速掌握任意 Android 应用的抓包

抓包是流量分析的基础&#xff0c;也是安全研究重要的一环。抓包软件有很多种&#xff0c;如 Burpsuite、mitmproxy 以及 Fiddle&#xff0c;抓包方式常见的有设置系统代理、AP 热点抓包、透明代理等。不同方式有不同优缺点&#xff0c;也有不同的应用场景。相信很多安全研究者…

Google Analytics | 学习笔记

一.简介 1.什么是GA&#xff1f; 是谷歌开发的一款分析网页流量的工具&#xff0c;可以帮助网站解决数据分析与统计的问题&#xff0c;并且将这些数据可视化展现报告出来&#xff0c;帮助网站商家更好的分析受众&#xff0c;流量等&#xff0c;从而更好地进行运营网站营销等 …

UV统计的学习

12.1 、UV统计-HyperLogLog 首先我们搞懂两个概念&#xff1a; UV&#xff1a;全称Unique Visitor&#xff0c;也叫独立访客量&#xff0c;是指通过互联网访问、浏览这个网页的自然人。1天内同一个用户多次访问该网站&#xff0c;只记录1次。 PV&#xff1a;全称Page View&am…

大龄考生上岸浙大MPA的“曲线救国”策略

先来介绍一下我个人的背景把&#xff0c;我是通过参加浙大提前批面试获得A资格&#xff0c;笔试接近两百分上岸MPA项目的。说起来我的个人优势真的不多&#xff0c;只是一个普通一本&#xff0c;不是什么211/985的名校&#xff0c;所以就对浙大有一种向往&#xff0c;使得自己的…

【数据结构】1.4 算法和算法分析

文章目录1. 算法的定义及特性算法的特性算法设计的要求2. 算法的时间复杂度分析算法时间复杂度的基本方法算法时间复杂度分析例题算法时间复杂度的计算3. 算法的空间复杂度1. 算法的定义及特性 算法的定义 对特定问题求解方法和步骤的一种描述&#xff0c;它是指令的有限序列…

C++:String类应用

string对象的构造 //string() string(const string &s) string(const char *s) string(first,last) void TestString01() {string s1;string s2("hello");string s3(s2);const char* p "hello";string s4(p, p 2);cin >> s1;cout << …

微信小程序 Springboot旅游景点酒店预订管理系统 java

功能模块划分 &#xff08;1&#xff09;用户信息管理模块 用户管理模块主要是对用户信息进行管理。包括&#xff1a; 用户的注册&#xff1a;实现用户信息的注册&#xff0c;用户注册是的信息校验&#xff0c;用户信息的保存。 用户的登录&#xff1a;检验用户是否为该网站的合…

如何打造优秀高绩效的团队?Google亚里士多德计划揭开谜底!

研究人员通过亚里士多德计划开展研究&#xff0c;通过对大量团队效率进行定性&#xff08;360主观评估&#xff09;与定量&#xff08;产出成果度量&#xff09;结合的统计评估&#xff0c;筛选出左右着团队动态的五个关键支柱&#xff1a;心理安全、可靠性、结构和清晰度、意义…

Nginx与Upstream之间产生大量TIME_WAIT连接的解决办法

1. 现象 Nginx反向代理了一个Java服务&#xff0c;QPS大概是200&#xff0c;问题发生时的Nginx配置&#xff1a; location / {proxy_pass http://192.168.3.4:18600; }在上游Java服务器上可以观察到大量&#xff08;约2000个&#xff09;的TIME_WAIT状态的网络连接 从Nginx…

一位十年测试老前辈的修炼之路,希望能帮你点清现实

对于刚进入软件测试工作岗位的新人&#xff0c;如何快速、健康的在职业道路上成长&#xff0c;作者谈了几点自己看法&#xff1a; 1、兴趣是最好的老师 对于软件测试工作&#xff0c;通常是比较枯燥的&#xff0c;如果没有兴趣很难做到持久。 我最近参与了一个软件测试项目&a…

Plecs电力电子仿真专业教程-第一季 第三节 Plecs界面介绍

Plecs电力电子仿真专业教程-第一季 第三节 Plecs界面介绍 Plecs仿真软件主要包含两个部分&#xff1a;元件库窗口和电路图编辑窗口。元件库窗口主要用于选择仿真所用到的电子元器件&#xff0c;通过拖拽的方式可以将所需要的元器件放置在主电路图窗口中。 主界面窗口如下&…

网络类型、路由封装实验

实验1. 拓扑搭建2. 配置各路由器物理接口IP地址边界路由器到ISP通测试PAP认证CHAP认证R3与R5间使用HDLC封装R1与R4为GRE环境R1、R2、R3为MGRE环境私有网络基于RIP全网可达给PC配置IP地址测试ping通性环境&#xff1a;华为模拟器 实验要求 1. 拓扑搭建 2. 配置各路由器物理接口…

【目标检测】MMYOLO | 如何使用 MMYOLO 训练模型

文章目录一、MMYOLO 简介1.1 MMYOLO 的安装和简单训练1.2 详细配置参数1.3 构建 Cat 数据集的 Config 文件1.3.1 数据集分布可视化1.3.2 Anchor-based 方法中 anchor 尺寸的优化1.3.3 可视化数据处理二、MMYOLO 的框架结构2.1 以 YOLOv5 为例来说明 MMYOLO 的框架结构2.1.1 Bac…