java indexeddb_IndexedDB使用与出坑指南

java indexeddb_IndexedDB使用与出坑指南概述本文通过对 IndexedDB 的使用方法和使用场景进行相关介绍 对常见的问题进行解答 同时 因为 MDN 中的相关文档缺乏相关逻辑性 所以不容易理解 本文将通过项目中常见的数据存储和操作需求来进行内容组织 读者能够通过本文学会在项目中正确的使用 IndexedDB 给应用带来的本地存储能力 并且避免一些常见的问题 原因 开发者需要在本地进行永久存储当我们进行一些较大的 SPA 页面开发时 我们会需要进行一

概述

本文通过对IndexedDB的使用方法和使用场景进行相关介绍,对常见的问题进行解答。

同时,因为MDN中的相关文档缺乏相关逻辑性,所以不容易理解。本文将通过项目中常见的数据存储和操作需求来进行内容组织。

读者能够通过本文学会在项目中正确的使用IndexedDB,给应用带来的本地存储能力,并且避免一些常见的问题。

原因:开发者需要在本地进行永久存储

当我们进行一些较大的SPA页面开发时,我们会需要进行一些数据的本地存储。

当数据量不大时,我们可以通过SessionStorage或者LocalStorage来进行存储,但是当数据量较大,或符合一定的规范时,我们可以使用数据库来进行数据的存储。

在浏览器提供的数据库中,共有web sql和IndexedDB两种。相较于HTML5已经废弃的web sql来说,更推荐大家使用IndexedDB。

结构

下面,我们通过一张图来了解下,IndexedDB整体的结构。

637540a03a903ae603a7cad10460a0e8.png

类比sql型数据库,IndexedDB中的DB(数据库)就是sql中的DB,而Object Store(存储空间)则是数据表,Item则等于表中的一条记录。

使用IndexedDB

现在,我们将其根据IndexedDB的结构来对其操作进行介绍,能让大家对这个存储空间有一个初步的了解。我们主要介绍:

数据库操作

数据表操作

数据操作

数据库操作

创建或打开数据库

使用IndexedDB第一步,就是创建或打开一个数据库。我们使用window.indexedDB.open(DBName)这个API来打进行操作。具体示例如下:

const request = window.indexedDB.open(‘test’);

request.onupgradeneeded = function (event) {

}

request.onsuccess = function(event) {

//request === event.target;

}

request.onerror = function(event) {}

调用此接口时,如果当前数据库不存在,则会创建一个新的数据库。

当数据库建立连接时,会返回一个IDBOpenDBRequest对象。

在连接建立成功时,会触发onsuccess事件,其中函数参数event的target属性就是request对象。

而在数据库创建或者版本更新时,会触发onupgradeneeded事件。

更新数据库版本号

window.indexedDB.open的第二个参数即为版本号。在不指定的情况下,默认版本号为1。具体示例如下:

const request = window.indexedDB.open(‘test’, 2);

在需要更新数据库的schema(模式)时,需要更新版本号。此时我们指定一个高于之前版本的版本号,就会触发onupgradeneeded事件。类似的,当此数据库不存在时,也会触发此事件并且将版本更新到置顶版本。

我们需要注意的是,版本号是一个Unsigned long long数字,这意味着它可以是一个非常大的整数。但是,它不能是一个小数,否则它将会被转为最近的整数,同时有可能导致onUpgradeneeded事件不触发(bug)。

存储空间操作

创建存储空间

我们使用createObjectStore来创建一个存储空间。同时,使用createIndex来创建它的索引。具体示例如下:

var request = window.indexedDB.open(‘test’, 1);

request.onupgradeneeded = function (event) {

var db = event.target.result;

var objectStore = db.createObjectStore(‘table1’, {keyPath: ‘id’, autoIncrement: true});

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

}

request.onerror = function (event) {

alert(“Why didn’t you allow my web app to use IndexedDB?!”);

};

注:只能在onupgradeneeded回调函数中创建存储空间,而不能在数据库打开后的success回调函数中创建。

通过createObjectStore能够创建一个存储空间。接受两个参数:

第一个参数,存储空间的名称,即我们上面的customers。

第二个参数,指定存储的keyPath值为存储对象的某个属性,这个属性能够在获取存储空间数据的时候当做key值使用。autoIncrement指定了key值是否自增(当key值为默认的从1开始到2^53的整数时)。

而createIndex能够给当前的存储空间设置一个索引。它接受三个参数:

第一个参数,索引的名称。

第二个参数,指定根据存储数据的哪一个属性来构建索引。

第三个属性, options对象,其中属性unique的值为true表示不允许索引值相等。

数据操作

事务

在IndexedDB中,我们也能够使用事务来进行数据库的操作。事务有三个模式(常量已经弃用):

readOnly,只读。

readwrite,读写。

versionchange,数据库版本变化。

我们创建一个事务时,需要从上面选择一种模式,如果不指定的话,则默认为只读模式。具体示例如下:

const transaction = db.transaction([‘customers’], ‘readwrite’);

事务函数transaction的第一个参数为需要关联的存储空间,第二个可选参数为事务模式。与上面类似,事务成功时也会触发onsuccess函数,失败时触发onerror函数。

事务的操作都是原子性的。

增加数据

当存储空间初始化完成后,我们可以把数据放入存储空间中。直接调用add方法就可以将数据放入存储空间内,具体示例如下:

var request = window.indexedDB.open(‘test’, 1);

request.onsuccess = function (event) {

var db = event.target.result;

var transaction = db.transaction([‘table1’], ‘readwrite’);

var objectStore = transaction.objectStore(‘table1’);

var index = objectStore.index(‘name’);

objectStore.add({name: ‘a’, age: 10});

objectStore.add({name: ‘b’, age: 20});

}

注:add方法中的第二个参数key值是指定存储空间中的keyPath值,如果data中包含keyPath值或者此值为自增值,那么可以略去此参数。

查找数据

通过特定值获取数据

当我们需要从存储空间获取数据时,我们可以通过以下的方法:

var request = window.indexedDB.open(‘test’, 1);

request.onsuccess = function (event) {

var db = event.target.result;

var transaction = db.transaction([‘table1’], ‘readwrite’);

var objectStore = transaction.objectStore(‘table1’);

var request = objectStore.get(1);

request.onsuccess = function (event) {

// 对 request.result 做些操作!

console.log(request.result);

};

request.onerror = function (event) {

// 错误处理!

};

}

通过游标获取数据

当你需要便利整个存储空间中的数据时,你就需要使用到游标。游标使用方法如下:

var request = window.indexedDB.open(‘test’, 1);

request.onsuccess = function (event) {

var db = event.target.result;

var transaction = db.transaction([‘table1’], ‘readwrite’);

var objectStore = transaction.objectStore(‘table1’);

var request = objectStore.openCursor();

request.onsuccess = function (event) {

var cursor = event.target.result;

if (cursor) {

// 使用Object.assign方法是为了避免控制台打印时出错

console.log(Object.assign(cursor.value));

cursor.continue();

}

};

request.onerror = function (event) {

// 错误处理!

};

}

使用游标时有一个需要注意的地方,当游标便利整个存储空间但是并未找到给定条件的值时,仍然会触发onsuccess函数。

openCursor和openKeyCursor有两个参数:

第一个参数,遍历范围,指定游标的访问范围。该范围通过一个IDBKeyRange参数的方法来获取。

遍历范围参数具体示例如下:

// 匹配值 key === 1

const singleKeyRange = IDBKeyRange.only(1);

// 匹配值 key >= 1

const lowerBoundKeyRange = IDBKeyRange.lowerBound(1);

// 匹配值 key > 1

const lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, true);

// 匹配值 key < 2

const upperBoundOpenKeyRange = IDBKeyRange.upperBound(2, true);

// 匹配值 key >= 1 && key < 2

const boundKeyRange = IDBKeyRange.bound(1, 2, false, true);

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

const cursor = event.target.result;

if (cursor) {

// Do something with the matches.

cursor.continue();

}

};

第二个参数,便利顺序,指定游标便利时的顺序和处理相同id(keyPath属性指定字段)重复时的处理方法。改范围通过特定的字符串(IDBCursor的常量已经弃用)来获取。其中:

next,从前往后获取所有数据(包括重复数据)

prev,从后往前获取所有数据(包括重复数据)

nextunique,从前往后获取数据(重复数据只取第一条,索引重复即认为重复,下同)

prevunique,从后往前获取数据(重复数据只取第一条)

遍历顺序参数具体示例如下:

var request = window.indexedDB.open(‘test’, 1);

request.onsuccess = function (event) {

var db = event.target.result;

var transaction = db.transaction([‘table1’], ‘readwrite’);

var objectStore = transaction.objectStore(‘table1’);

var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(1, false);

var request = objectStore.openCursor(lowerBoundOpenKeyRange, IDBCursor.PREV);

request.onsuccess = function (event) {

var cursor = event.target.result;

if (cursor) {

// 使用Object.assign方法是为了避免控制台打印时出错

console.log(Object.assign(cursor.value));

cursor.continue();

}

};

request.onerror = function (event) {

// 错误处理!

};

}

使用索引

在前面构建数据库时,我们创建了两个索引。现在我们也可以通过索引来进行数据检索。他的本质还是通过之前获取数据的API来进行,只是将原来使用的keyPath属性转换成为了索引指定的属性。具体示例如下:

var request = window.indexedDB.open(‘test’, 1);

request.onsuccess = function (event) {

var db = event.target.result;

var transaction = db.transaction([‘table1’], ‘readwrite’);

var objectStore = transaction.objectStore(‘table1’);

var index = objectStore.index(‘name’);

// 第一种,get方法

index.get(‘a’).onsuccess = function (event) {

console.log(event.target.result);

}

// 第二种,普通游标方法

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

console.log(‘openCursor:’, event.target.result.value);

}

// 第三种,键游标方法,该方法与第二种的差别为:普通游标带有value值表示获取的数据,而键游标没有

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

console.log(‘openKeyCursor:’, event.target.result);

}

}

修改数据

当需要修改存储空间中的数据时,我们可以使用以下的API:

var objectStore = transaction.objectStore(“customers”);

var request = objectStore.put(data);

request.onsuccess = function (event) {

}

注:put方法不仅能够修改现有数据,也能够往存储空间中增加新的数据。

删除数据

当我们需要删除已经无用的数据时,我们可以通过以下方法:

var objectStore = transaction.objectStore(“customers”);

var request = objectStore.delete(name);

request.onsuccess = function (event) {

}

异常处理

在浏览器有如下操作的情况下,indexedDB可能会出现异常:

用户清除浏览器缓存

存储空间超过大小限制

此时,需要对错误进行捕获,并且对用户进行提示。此章节不是本文重点,再此略过。

扩展须知

取值相关

key值能够接受的数据类型

在IndexedDB中,键值对中的key值可以接受以下几种类型的值:

number

data

string

binary

array

具体说明可以见文档此处。

key path能够接受的数据类型

当一个key值变为主键,即keyPath时,它的值就只能是以下几种:

Blob

File

Array

String

注:空格不能出现在key path中。

具体说明可以见文档此处。

value能够接受的数据类型

在IndexedDB中,value能够接受ECMA-262中所有的类型的值,例如String,Date,ImageDate等。

事务相关

事务中断后,会不会影响key值的自增

IndexedDB在没有指定key值的时候就会采用自增的key值。如果一个事务在中途中断,那么key值的自增将会从中断的事务开始前的key开始。

安全相关

IndexedDB也受到浏览器同源策略的限制。

用户相关

清空缓存

用户在清除浏览器缓存时,可能会清除IndexedDB中相关的数据。

访问权限

部分浏览器如Safari手机版隐私模式在访问IndexedDB时,可能会出现由于没有权限而导致的异常(LocalStorage也会),需要进行异常处理。

总结

IndexedDB在本地存储中有着无可替代的作用,是替代关系型数据库web sql的产品,能够对大量数据进行存储。在许多需要运用离线存储的场景下,它能够给我们提供有效的支撑。

但是,IndexedDB在使用过程中仍然需要避免可能会出现的一些问题,或者对可能导致的不利影响有一定的容错处理。这样才不会对应用产生重大影响。

参考文献

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233680.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • tomcat 宕机原因排查

    tomcat 宕机原因排查一、近期突然发生的现象。可能原因:被恶意攻击或利用排查方式:1、运行tomcat并查看tomcat用户是否开启了陌生进程,同时看下tomcat相关目录、系统/tmp目录有没有陌生文件2、将该tomcat的访问转向一个不匹配的tomcat,然后通过查看错误日志,看是否有频繁…

    2022年7月26日
    42
  • html幻灯片图片切换效果代码,javascript实现图片切换的幻灯片效果源代码[通俗易懂]

    html幻灯片图片切换效果代码,javascript实现图片切换的幻灯片效果源代码[通俗易懂]网页上有许多图片切换的幻灯片效果,它们大多用flash实现,那javascript能不能实现他们呢,当然可以,我自己写了一个,和大家一同分享废话少说,看代码sx.activex.imagefade={init:function(imga,fadeint,fadeoutt){varti=newArray();for(vari=0;iti[i]=newImage();ti[i].src=img…

    2022年7月13日
    16
  • 微信小程序自定义组件

    微信小程序自定义组件

    2021年6月11日
    139
  • C++ eigen_c++第三方库

    C++ eigen_c++第三方库前言Eigen就是一个线性代数的C++库。它对矩阵(MatrixMatrix)和向量(VectorVector)等相关线性代数的运算操作进行了比较系统的实现。一、矩阵1.定义矩阵模板函数共包含六个参数template<typename_Scalar,int_Rows,int_Cols,int_Options,int_MaxRows,int_MaxC…

    2022年10月19日
    2
  • 平衡二叉树的数据结构_红黑树数据结构

    平衡二叉树的数据结构_红黑树数据结构红黑树Java集合系列之TreeMap详细介绍(源码解析)和使用示例代码来自算法第四版红黑树并不追求“完全平衡”——它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。红黑树实际上是由2-3-4树转换而来,红黑树能够以O(log2n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,还有一些更好的,但实现起来更复杂的数据

    2022年8月30日
    1
  • 静态方法中可以访问非静态成员变量_多线程局部变量会不会互相影响

    静态方法中可以访问非静态成员变量_多线程局部变量会不会互相影响静态内部类访问包含它的外部类的非静态成员变量时,可以通过new外部类().成员的方式访问,这是因为静态的只能访问静态的,因为他们在对象没创建前就存在了。如果想访问非静态的则必须初始化该对象,因为只有初始化后对象在内存才存在(静态的除外)…

    2022年8月31日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号