indexedDB 基本使用

2024-03-14 02:32
文章标签 使用 基本 indexeddb

本文主要是介绍indexedDB 基本使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

indexedDB 简介: 


indexedDB 是一种使用浏览器存储大量数据的方法。它创造的数据可以被查询,并且可以离线使用。


indexedDB 有以下特点:


  1. indexedDB 是 WebSQL 数据库的取代品

  2. indexedDB遵循同源协议(只能访问同域中存储的数据,而不能访问其他域的)

  3. API包含异步API和同步API两种:多数情况下使用异步API; 同步API必须同 WebWorkers 一起使用, 目前没有浏览器支持同步API

  4. indexedDB 是事务模式的数据库, 使用 key-value 键值对储存数据

  5. indexedDB 不使用结构化查询语言(SQL). 它通过索引(index)所产生的指针(cursor)来完成查询操作


一、使用indexedDB的基本模式


  1. 打开数据库并且开始一个事务。

  2. 创建一个 objecStore。

  3. 构建一个请求来执行一些数据库操作,像增加或提取数据等。

  4. 通过监听正确类型的 DOM 事件以等待操作完成。

  5. 在操作结果上进行一些操作(可以在 request 对象中找到)


二、创建、打开数据库


indexedDB 存在于全局对象window上, 它最重要的一个方法就是open方法, 该方法接收两个参数:


  • dbName // 数据库名称 [string]

  • version // 数据库版本 [整型number]


var DB_NAME = 'indexedDB-test', VERSION = 1, db;

var request = indexedDB.open(DB_NAME, VERSION);

request.onsuccess = function(event) {

    db = event.target.result;

    // console.log(event.target === request); // true

    db.onsuccess = function(event) {

        console.log('数据库操作成功!');

    };

    db.onerror = function(event) {

        console.error('数据库操作发生错误!', event.target.errorCode);

    };

    console.log('打开数据库成功!');

};

request.onerror = function(event) {

    console.error('创建数据库出错');

    console.error('error code:', event.target.errorCode);

};

request.onupgradeneeded = function(event) {

   // 更新对象存储空间和索引 ....

};


若是本域下不存在名为DB_NAME的数据库,则上述代码会创建一个名为DB_NAME、版本号为VERSION的数据库; 触发的事件依次为: upgradeneeded、 success.


若是已存在名为DB_NAME的数据库, 则上述代码会打开该数据库; 只触发success/error事件,不会触发upgradeneeded事件. db是对该数据库的引用.


三、创建对象存储空间和索引


在关系型数据库(如mysql)中,一个数据库中会有多张表,每张表有各自的主键、索引等;


在key-value型数据库(如indexedDB)中, 一个数据库会有多个对象存储空间,每个存储空间有自己的主键、索引等;


创建对象存储空间的操作一般放在创建数据库成功回调里:


request.onupgradeneeded = function(event) { // 更新对象存储空间和索引 ....

    var database = event.target.result;

    var objectStore = database.createObjectStore("movies", { keyPath"id" });

    objectStore.createIndex('alt', 'alt', { uniquetrue });

    objectStore.createIndex('title', 'title', { uniquefalse });

};


onupgradeneeded 是我们唯一可以修改数据库结构的地方。在这里面,我们可以创建和删除对象存储空间以及构建和删除索引。


在数据库对象database上,有以下方法可供调用:


  1. createObjectStore(storeName, configObj) 创建一个对象存储空间

    1. storeName // 对象存储空间的名称 [string]

    2. configObj // 该对象存储空间的配置 [object] (其中的keyPath属性值,标志对象的该属性值唯一)

  2. createIndex(indexName, objAttr, configObj) 创建一个索引

    1. indexName // 索引名称 [string]

    2. objAttr // 对象的属性名 [string]

    3. configObj // 该索引的配置对象 [object]


四、增加和删除数据


对数据库的操作(增删查改等)都需要通过事务来完成,事务具有三种模式:


  • readonly 只读(可以并发进行,优先使用)

  • readwrite 读写

  • versionchange 版本变更


向数据库中增加数据


前面提到,增加数据需要通过事务,事务的使用方式如下:


var transaction = db.transaction(['movies'], 'readwrite');

transaction.oncomplete = function(event) {

    console.log('事务完成!');

};

transaction.onerror = function(event) {

    console.log('事务失败!', event.target.errorCode);

};

transaction.onabort = function(event) {

    console.log('事务回滚!');

};



insert-data-web数据库对象的transaction()方法接收两个参数:


  • storeNames // 对象存储空间,可以是对象存储空间名称的数组,也可以是单个对象存储空间名称,必传 [array|string]

  • mode // 事务模式,上面提到的三种之一,可选,默认值是readonly [string]


这样,我们得到一个事务对象transaction, 有三种事件可能会被触发: complete, error, abort. 现在,我们通过事务向数据库indexedDB-test的 对象存储空间movies中插入数据:


var objectStore = transaction.objectStore('movies');  // 指定对象存储空间

var data = [{

  "title""寻梦环游记",

  "year""2017",

  "alt""https://movie.douban.com/subject/20495023/",

  "id""20495023"

}, {

  "title""你在哪",

  "year""2016",

  "alt""https://movie.douban.com/subject/26639033/",

  "id""26639033"

}, {

  "title""笔仙咒怨",

  "year""2017",

  "alt""https://movie.douban.com/subject/27054612/",

  "id""27054612"

}];

data.forEach(function(item, index){

    var request = objectStore.add(item);

    request.onsuccess = function(event) {

        console.log('插入成功!', index);

        console.log(event.target.result, item.id); // add()方法调用成功后result是被添加的值的键(id)

    };

});


通过事务对象transaction,在objectStore()方法中指定对象存储空间,就得到了可以对该对象存储空间进行操作的对象objectStore.


向数据库中增加数据,add()方法增加的对象,若是数据库中已存在相同的主键,或者唯一性索引的键值重复,则该条数据不会插入进去;


增加数据还有一个方法: put(), 使用方法和add()不同之处在于,数据库中若存在相同主键或者唯一性索引重复,则会更新该条数据,否则插入新数据。


从数据库中删除数据


删除数据使用delete方法,同上类似:


var request =

    db.transaction(['movies'], 'readwrite')

      .objectStore('movies')

      .delete('27054612');  // 通过键id来删除

request.onsuccess = function(event) {

    console.log('删除成功!');

    console.log(event.target.result);

};


从数据中获取数据


获取数据使用get方法,同上类似:


var request =

    db.transaction('movies')

       .objectStore('movies')

       .get('9999682');  // 通过键alt来获取

request.onsuccess = function(event) {

    console.log('获取成功!', event.target.result);

};


五、使用索引


在前面,我们创建了两个索引alt和title, 配置对象里面的unique属性标志该值是否唯一


现在我们想找到alt属性值为https://movie.douban.com/subject/26639033/的对象,就可以使用索引。


var alt = 'https://movie.douban.com/subject/26639033/';

var objectStore = db.transaction('movies').objectStore('movies');  // 打开对象存储空间

var index = objectStore.index('alt');  // 使用索引'alt'

var request = index.get(alt);          // 创建一个查找数据的请求

request.onsuccess = function(event) {

    console.log('The result is:', event.target.result);

};

var noDataTest = index.get('testalt');  // 没有该对象时的测试

noDataTest.onsuccess = function(event) {

    console.log('success! result:', event.target.result);

};

noDataTest.onerror = function(event) {

    console.log('error! event:', event);

};



使用唯一性索引,我们可以得到唯一的一条数据(或者undefined),那么使用非唯一性索引呢?

我们向数据库中插入一条数据,使title重复:


db.transaction('movies', 'readwrite').objectStore('movies')

.add({ alt'https://movie.douban.com/subject/27054612121/',

    title'寻梦环游记',

    year'2017',

    id'123456789'

})

.onsuccess = function(event) { console.log('插入成功!'); };


使用索引title获取title值为寻梦环游记的对象:


var indexName = 'title', title = '寻梦环游记';

var objectStore = db.transaction('movies').objectStore('movies');

var index = objectStore.index(indexName);  // 使用索引'alt'

var request = index.get(title);          // 创建一个查找数据的请求

request.onsuccess = function(event) {

    console.log('The result is:', event.target.result);

};


我们得到的是键值最小的那个对象.


使用一次索引,我们只能得到一条数据; 如果我们需要得到所有title属性值为寻梦环游记的对象,我们可以使用游标.


六、使用游标


得到一个可以操作游标的请求对象有两个方法:


  • openCursor(keyRange, direction)

  • openKeyCursor(keyRange, direction)


这两个方法接收的参数一样, 两个参数都是可选的: 第一个参数是限制值得范围,第二个参数是指定游标方向


游标的使用有以下几处:


  • 在对象存储空间上使用: var cursor = objectStore.openCursor()

  • 在索引对象上使用: var cursor = index.openCursor()


在对象存储空间上使用游标

使用游标常见的一种模式是获取对象存储空间上的所有数据.


var list = [];

var objectStore = db.transaction('movies').objectStore('movies');

objectStore.openCursor().onsuccess = function(event) {

    var cursor = event.target.result;

    if (cursor) {

        console.log('cursor:', cursor);

        list.push(cursor.value);

        cursor.continue();

    } else {

        console.log('Get all data:', list);

    }

};


使用游标时,需要在成功回调里拿到result对象,判断是否取完了数据:若数据已取完,result是undefined; 若未取完,则result是个IDBCursorWithValue对象,需调用continue()方法继续取数据。 也可以根据自己需求, 对数据进行过滤。


在indexedDB2规范中,在对象存储空间对象上纳入了一个getAll()方法,可以获取所有对象:


objectStore.getAll().onsuccess = function(event) {

    console.log('result:', event.target.result);

};


在索引上使用游标


接着本文上述使用索引的例子,在索引title上使用openCursor()方法时,若不传参数,则会遍历所有数据,在成功回调中的到的result对象有以下属性:


  • key 数据库中这条对象的title属性值

  • primaryKey 数据库中这条对象的alt值

  • value 数据库中这条对象

  • direction openCursor()方法传入的第二个对象,默认值为next


source IDBIndex对象 举例如下:


var index = db

.transaction('movies')

.objectStore('movies').index('title');

index.openCursor().onsuccess = function(event) {

  var cursor = event.target.result;

  if (cursor) {

      console.log('cursor:', cursor);

      cursor.continue();

  }

};


在索引title上使用openKeyCursor()方法,若不传参数,同样也会遍历所有数据,result对象属性如下:


  • key 数据库中这条对象的title属性值

  • primaryKey 数据库中这条对象的alt值

  • direction openCursor()方法传入的第二个对象,默认值为next

  • source altBIndex对象


和openCursor()方法相比,得到的数据少一个value属性,是没有办法得到存储对象的其余部分


前面说到,我们要根据索引title获取所有title属性值为寻梦环游记的对象,要使用游标,而又不想遍历所有数据,这时就要用到openCursor()的第一个参数: keyRange


keyRange是限定游标遍历的数据范围,通过IDBKeyRange的一些方法设置该值:


var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];

var index = db

.transaction('movies')

.objectStore('movies').index('title');

index.openCursor(singleKeyRange).onsuccess = function(event) {

var cursor = event.target.result;

if (cursor) {

console.log('cursor.value:', cursor.value);

list.push(cursor.value);

cursor.continue();

} else {

    console.log('list:', list);

}

};


IDBKeyRange其他一些方法:


// 匹配所有在 "Bill" 前面的, 包括 "Bill"

var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");

 

// 匹配所有在 “Bill” 前面的, 但是不需要包括 "Bill"

var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);

 

// 匹配所有在'Donna'后面的, 但是不包括"Donna"

var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);

 

// 匹配所有在"Bill" 和 "Donna" 之间的, 但是不包括 "Donna"

var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);


更多请参考 MDN|IDBKeyRange


游标默认遍历方向是按主键从小到大,有时候我们倒序遍历,此时可以给openCursor()方法传递第二个参数: direction: next|nextunique|prev|prevunique


var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];

var index = db

.transaction('movies')

.objectStore('movies').index('title');

index.openCursor(singleKeyRange, 'prev').onsuccess = function(event) {

var cursor = event.target.result;

if (cursor) {

console.log('cursor.value:', cursor.value);

list.push(cursor.value);

cursor.continue();

} else {

    console.log('list:', list);

}

};


传了prev的结果是按倒序遍历的.


因为 “name” 索引不是唯一的,那就有可能存在具有相同 name 的多条记录。 要注意的是这种情况不可能发生在对象存储空间上,因为键必须永远是唯一的。 如果你想要在游标在索引迭代过程中过滤出重复的,你可以传递 nextunique(或prevunique, 如果你正在向后寻找)作为方向参数。 当 nextunique 或是 prevunique 被使用时,被返回的那个总是键最小的记录。


var singleKeyRange = IDBKeyRange.only("寻梦环游记"), list = [];

var index = db

.transaction('movies')

.objectStore('movies').index('title');

index.openCursor(singleKeyRange, 'prevunique').onsuccess = function(event) {

var cursor = event.target.result;

if (cursor) {

console.log('cursor.value:', cursor.value);

list.push(cursor.value);

cursor.continue();

} else {

    console.log('list:', list);

}

};



七、关闭和删除数据库


关闭数据库只需要在数据库对象db上调用close()方法即可


db.close();


关闭数据库后,db对象仍然保存着该数据库的相关信息,只是无法再开启事务(调用开启事务方法会报错,提示数据库连接已断开):



删除数据库则需要使用indexedDB.deleteDatabase(dbName)方法


window.indexedDB.deleteDatabase(dbName);


八、indexedDB的局限性


以下情况不适合使用IndexedDB


  • 全球多种语言混合存储。国际化支持不好。需要自己处理。

  • 和服务器端数据库同步。你得自己写同步代码。

  • 全文搜索。


注意,在以下情况下,数据库可能被清除:


  • 用户请求清除数据。

  • 浏览器处于隐私模式。最后退出浏览器的时候,数据会被清除。

  • 硬盘等存储设备的容量到限。

  • 不正确的

  • 不完整的改变.


总结


  1. 使用indexedDB.open(dbName, version)打开一个数据库连接

  2. 使用indexedDB.deleteDatabase(dbName)删除一个数据库

  3. 在数据库对象db上使用createObjectStore(storeName, config)创建对象存储空间

  4. 在对象存储空间objectStore上使用createIndex(indexName, keyName, config)创建索引

  5. 对数据库的操作都需要通过事务完成: var transction = db.transaction([storeName], mode)

  6. 数据库的增删改查均通过objectStore对象完成,var objectStore = transaction.objectStore(storeName)

  7. 对数据库数据操作有: add()、get()、delete()、put等方法

  8. 查找数据可以使用索引: objectStore.index(indexName)

  9. 遍历和过滤数据可以使用游标: openCursor(keyRange, direction)


参考


  • IndexedDB的基本概念-MDN

  • 使用 IndexedDB-MDN

  • IndexedDB API接口-MDN

  • Indexed Database API 2.0 – w3c


这篇关于indexedDB 基本使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/806947

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联