摘要:在不指定的情况下,默认版本号为。具体示例如下在需要更新数据库的模式时,需要更新版本号。此时我们指定一个高于之前版本的版本号,就会触发事件。数据操作事务在中,我们也能够使用事务来进行数据库的操作。
概述
本文通过对IndexedDB的使用方法和使用场景进行相关介绍,对常见的问题进行解答。
同时,因为MDN中的相关文档缺乏相关逻辑性,所以不容易理解。本文将通过项目中常见的数据存储和操作需求来进行内容组织。
读者能够通过本文学会在项目中正确的使用IndexedDB,给应用带来的本地存储能力,并且避免一些常见的问题。
原因:开发者需要在本地进行永久存储当我们进行一些较大的SPA页面开发时,我们会需要进行一些数据的本地存储。
当数据量不大时,我们可以通过SessionStorage或者LocalStorage来进行存储,但是当数据量较大,或符合一定的规范时,我们可以使用数据库来进行数据的存储。
在浏览器提供的数据库中,共有web sql和IndexedDB两种。相较于HTML5已经废弃的web sql来说,更推荐大家使用IndexedDB。
结构下面,我们通过一张图来了解下,IndexedDB整体的结构。
类比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在使用过程中仍然需要避免可能会出现的一些问题,或者对可能导致的不利影响有一定的容错处理。这样才不会对应用产生重大影响。
参考文献浏览器的同源策略
使用indexedDB MDN入门
IndexedDB API参考
W3C IndexedDB 2.0规范
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/80378.html
摘要:问题描述我自己以扩展为基础,封装了一个异步任务服务器框架,数据库操作使用扩展,但是在插入数据的时候,出现了异常情况,具体状况如下表引擎的正常插入,没有问题表引擎查询都可以的,但是插入失败,出现回滚现象,字段变化,表的变化,正常返回解决过程监 问题描述 我自己以swoole扩展为基础,封装了一个异步任务服务器框架,数据库操作使用pdo扩展,但是在插入数据的时候,出现了异常情况,具体状况如...
摘要:只要满足规范的放入该容器,马上就会被容器进行高效率的管理。根据康威定律,设计系统的组织时,最终产生的设计等价于组织的沟通结构,通俗来讲,团队的交流机制应该与架构分层交互机制相对应。 本博客 猫叔的博客,转载请申明出处 先来看看官网对它的定义。 Java平台企业版(Java EE)是社区驱动的企业软件的标准。Java EE是使用Java Community Process开发的,其中包括...
阅读 3123·2021-11-04 16:09
阅读 3041·2021-09-23 11:49
阅读 3577·2021-09-09 09:33
阅读 3528·2021-08-18 10:22
阅读 2019·2019-08-30 15:55
阅读 3593·2019-08-30 15:53
阅读 2636·2019-08-28 18:08
阅读 867·2019-08-26 18:18