使用游标

使用get()方法需要您知道您想要查询的数据的【键】。如果您想单步调试对象store的所有记录,您可以使用游标。如下所示:

var objectStore = db.transaction("customers").objectStore("customers");objectStore.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {alert("Name for SSN " + cursor.key + " is " + cursor.value.name);cursor.continue();}else {alert("No more entries!");}
};

openCursor()方法带有几个参数。首先,您可以使用【键】的范围对象来限制查询项目的范围,该对象稍后介绍。第二,您可以指定迭代方向。上例中,我们按照升序迭代遍历所有对象。游标的success处理有点特殊,游标对象本身是请求request的结果result(我们使用了速记,它是event.target.result)。那么实际的【键】key和【值】value可以在游标对象的属性key和value中找到。如果要继续运行,您必须为游标呼叫continue()方法。到达数据尾部时(或者打开的游标中没有数据),您仍然会得到success回调处理,但是该结果的属性是未定义的。

通常的做法是,查询一个对象store的所有数据,然后存放在数组中,如下所示:

var customers = [];objectStore.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {customers.push(cursor.value);cursor.continue();}else {alert("Got all customers: " + customers);}
};

注意:Mozilla也实现了getAll()方法来处理这种情况(还有getAllKeys(),现在已经隐藏到dom.indexedDB.experimental).这些不是IndexedDB标准的一部分,所以它们将来会消失。介绍这些是因为有用。下面代码精确地实现了同样的功能:

objectStore.getAll().onsuccess = function(event) {alert("Got all customers: " + event.target.result);
};

使用游标的属性值会带来一定的性能消耗,因为对象是被惰性创建的。当您使用getAll()方法时,Gecko必须一次性创建所有的对象。比如,如果您只是每个【键】感兴趣, 使用游标会比呼叫getAll()方法性能高很多。但是,如果您想要一个包含指定对象store的所有记录的数组,请使用getAll()方法。

使用索引

以ssn为主键,存储顾客数据是合理的,因为每个ssn的值具有唯一性。(这是否是一个好主意,暂且不讨论)。

如果您需要以来查询顾客信息的名字name,您需要迭代遍历数据库中的每个ssn,直到您找到。这样的方式查询速度会很慢,因此,您应该使用索引index。

var index = objectStore.index("name");index.get("Donna").onsuccess = function(event) {alert("Donna's SSN is " + event.target.result.ssn);
};

名字属性name不是唯一的,因此可能有多个记录的name值是“Donna”。此时,您将得到【键】最小的记录对应的name值。如果您需要访问指定name值的所有记录,您可以使用游标。您可以在index上打开两个不同类型的游标。一个常规的游标会映射(maps)index的属性值到对象store中的对象。一个【键】游标会映射index的属性值到对象store中对象的【键】。不同之处举例说明如下:

// Using a normal cursor to grab whole customer record objects
index.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// cursor.key is a name, like "Bill", and cursor.value is the whole object.alert("Name: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);cursor.continue();}
};// Using a key cursor to grab customer record object keys
index.openKeyCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// cursor.key is a name, like "Bill", and cursor.value is the SSN.// No way to directly get the rest of the stored object.//alert("Name: " + cursor.key + ", SSN: " + cursor.value);官方文档有误,在chrome和ff实测,应该是如下语句
    alert("Name: " + cursor.key + ", SSN: " + cursor.primaryKey);
cursor.continue();}
};

指定范围和游标的方向

如果您要指定游标的范围,可以使用IDBKeyRange对象并把它传递给openCursor() or openKeyCursor()的第一个参数。您可以把【键】的范围设置成只有一个单独的【键】,或者带有上限或者下限,或者上下限都有。上下界限可以封闭的(例如,【键】的范围包含边界值)或者开放的(例如,【键】的范围不包含边界值。工作方式如下所示:

// Only match "Donna"
var singleKeyRange = IDBKeyRange.only("Donna");// Match anything past "Bill", including "Bill"
var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");// Match anything past "Bill", but don't include "Bill"
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);// Match anything up to, but not including, "Donna"
var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);// Match anything between "Bill" and "Donna", but not including "Donna"
var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
index.openCursor(boundKeyRange).onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the matches.cursor.continue();}
};

有时候,您可能想按照降序而不是升序遍历数据集(默认的方向是升序)。切换遍历方向的功能已经被华丽丽的实现了,只需要把“prev”作为第二个参数传递给openCursor()。

objectStore.openCursor(boundKeyRange, "prev").onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the entries.cursor.continue();}
};

如果您只是想指定遍历方向而不需要过滤结果,您可以传递一个null给openCursor()作为第一个参数

objectStore.openCursor(null, "prev").onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the entries.cursor.continue();}
};

“name”索引值不具有唯一性,可能存在多个相同的值。注意,这种情况不能发生在对象store,因为【key】必须具有唯一性。如果您想在游标中过滤掉索引的多个重复值,您可以传递“nextunique”(或者“prevunique”,如果您要向前查询)作为方向参数。一旦用了“nextunique”或者“prevunique”,带有最小【键】的记录将被返回。

index.openKeyCursor(null, "nextunique").onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the entries.cursor.continue();}
};

了解方向参数的信息,请参考IDBCursor Constants

数据库版本变化然而web应用在另一个标签页中被打开。

当您的web应用有变更时,此种情况下,数据库也需要变更。此时,如果用户在一个标签页打开了旧的程序,

而在另一个标签页打开了新的程序,您应该考虑会发生什么问题。当您以高于现有数据库(版本号)的版本号为参数呼叫open()时,在更改数据库之前,所有其它已经打开的数据库必须显式通知该请求(阻塞事件将被触发,直到他们被关闭或者重新载入)。举例如下:

var openReq = mozIndexedDB.open("MyTestDatabase", 2);openReq.onblocked = function(event) {// If some other tab is loaded with the database, then it needs to be closed// before we can proceed.alert("Please close all other tabs with this site open!");
};openReq.onupgradeneeded = function(event) {// All other databases have been closed. Set everything up.db.createObjectStore(/* ... */);useDatabase(db);
};openReq.onsuccess = function(event) {var db = event.target.result;useDatabase(db);return;
};function useDatabase(db) {// Make sure to add a handler to be notified if another page requests a version// change. We must close the database. This allows the other page to upgrade the database.// If you don't do this then the upgrade won't happen until the user closes the tab.db.onversionchange = function(event) {db.close();alert("A new version of this page is ready. Please reload!");};// Do stuff with the database.
}

您也需要监听版本错误消息,以处理这样的情况:已经打开的应用,试图使用过期的版本号来打开数据库。

安全

IndexedDB使用同源策略,意味着把store绑定在创建它的网站上(通常,是站点的域或者子域),因此它不能被其它的站点访问。第三方的窗口可以访问宿主站点的IndexedDB store,除非浏览器设置为不接受第三方的cookies。

警惕浏览器关闭

如果浏览器关闭(因为用户点击了退出操作),硬盘包含的数据库将被意外删除,数据库无法访问,如下的事情会发生:

1涉及该数据库的每个事务会因为AbortError事件中止。作用与呼叫IDBTransaction.abort()相同。

2一旦所有的事务结束,数据库连接将关闭。

3最终,IDBDatabase对象代表的数据库连接会收到关闭事件。您可以使用IDBDatabase.onclose事件处理来监听该事件,这样您就能知道数据库什么时候意外关闭了。

以上描述的行为是新增的,只在下面的浏览器中有效:

Firefox 50, Google Chrome 31 (类似)

这些的版本之前的浏览器,事务会被悄悄的中止,不会触发关闭事件,因此也无法探测数据库何时被异常关闭。

因为用户可以在任何时候退出浏览器,这意味着您不能指望每个事务都顺利完成,而且在旧版本的浏览器中,您

甚至不知道它们是什么时候结束的。这意味着:

首先,在每个事务结束时,您应该小心地让数据库处于一致的状态。比如,假定您使用IndexedDB存储一个允许用户编辑的项目列表。用户编辑之后,您清除数据库中的原来的数据,把编辑之后的内容重新写入数据库。如果您在一个事务中清除数据库原有内容,而在另一个事务中向数据库写入新的内容。这很危险,浏览器将在清除数据库之后,新内容写入数据库之前被关闭,留给您一个空数据库。为避免此种情况,您应该在同一个事务中实施清除数据库内容和写入数据库内容。

其次,您永远不要把数据库事务绑定在unload事件。如果unload事件被关闭浏览器的行为触发,在unload事件处理中创建的任何事务将不会结束。为了在浏览器会话中保持一些信息,直观的方法是:打开浏览器时,读取数据库内容,用户操作时,记录数据的变更,关闭浏览器时,把新数据保存到数据库中。然而,此法行不通。数据库事务将在unload事件处理中被创建,但是因为它们是异步的,它们在执行之前将被中止。

实际上,没有方法来保证IndexedDB事务顺利完成,甚至在正常浏览器关闭的情况下。浏览器正常关闭时,您可以跟踪事务,添加beforeunload事件,这样,在unloading时,如果您的事务尚未完成,可以向用户提示警告信息。至少通过abort通知和IDBDatabase.onclose处理程序,您能知道(unload)是何时发生的。

本地化智能排序

Mozilla在Firefox 43+版本中已经实现了IndexedDB数据的本地化排序。默认地,IndexedDB根本不处理国际化字符串排序,所有的东西都作为英文排序。比如,b,á, z, a 排序如下:

a

b

z

á

显然不符合用户的预期——比如Aaron and Áaron应该是处于同一个通讯录的前后相邻的位置。实现适当的国际化排序需要把整个数据库读入内存,然后用客户端的javascript语言排序,效率并不够。

这个新的功能允许开发者在使用IDBObjectStore.createIndex()创建index时,指定本地语言集。这种情况下,使用游标遍历数据集时,而且您希望指定本地化智能排序,您可以使用对应的IDBLocaleAwareKeyRange。

IDBIndex也包含了一些新属性用来判断是否有本地化设置,它们是:locale(返回locale,或者null——如果没有设置本地化)和isAutoLocale(返回true——如果索引使用智能本地化创建——意味着使用平台的默认本地设置;否则false)。

注意:该特征隐藏于一个flag之中,如需开启和尝试,请到about:config并开启dom.indexedDB.experimental.

使用indexedDB(三)(翻译)相关推荐

  1. IndexedDB基本操作学习总结

    前言         最近在做一个脱机的项目,数据需要保存到前端,前端页面的操作大部分也是基于IndexdDB的,而该项目之前用的也是IndexedDB,在这里和大家分享下学习到的IndexdDB基本 ...

  2. 语言的翻译叫什么_独家整理MTI翻译硕士复试必考的翻译理论、策略和技巧

    小可爱们,今天讲的是每一个学校在MTI翻译硕士研究生复试都会考到的--翻译理论.策略.技巧.方法和工具等 考查形式: 复试笔试环节,理论名词解释+例子,比如 什么是接受美学?请举例子说明翻译如何体现这 ...

  3. web存储详解(cookie、sessionStorage、localStorage、indexedDB)

    目录 一.web存储概念简介 1. 什么是web存储? 2. 为什么需要web存储? 二.web存储详解 1. cookie 2. sessionStorage和localStorage (1). 相 ...

  4. python四级考试时间_四级英语考试如何准备呢?

    英语怎样才能过四级? 对于那些准备了很久就等这次考试拿个好成绩的同学,一定要认真看,绝对能帮到你们! (一)阅读 阅读是四六级的分数大户. 1.养成先看题目,再看阅读原文的习惯,掌握相关的阅读技巧. ...

  5. 前端识别验证码思路分析

    作者:莫卓颖 相信很多前端同学对于二维码识别.图像对比等这类高大上的图像识别技术望而生畏,觉得此类识别技术只能通过更加底仓的高级语言才能实现(诸如c等),本文试图从前端的角度出发介绍如何通过canva ...

  6. 腾讯 IVWEB 团队:前端识别验证码思路分析

    腾讯云技术社区-掘金主页持续为大家呈现云计算技术文章,欢迎大家关注! 作者:莫卓颖 相信很多前端同学对于二维码识别.图像对比等这类高大上的图像识别技术望而生畏,觉得此类识别技术只能通过更加底仓的高级语 ...

  7. logline: 是时候聊一聊前端的日志了

    原文:http://kezhen.info/2016/10/29/logline-logs-for-the-frontends/ 项目:https://github.com/latel/logline ...

  8. 论文阅读《Contextual-based Image Inpainting: Infer, Match, and Translate》

    介绍 从采样噪声生成照片般逼真的图像或在其他输入(例如图像,文本或标签)上进行调节的问题已经得到了大量的研究.但是现在生成高分辨率图像仍然是一项艰巨的任务.这主要是因为对像素的分布进行建模是困难的,并 ...

  9. 计算机英语二考研用书,考研英语二怎么准备?记过来人详细经验

    原标题:考研英语二怎么准备?记过来人详细经验 英语的提高是慢功夫,不要急躁.每天坚持读点英文,坚持背些单词,坚持做一篇阅读理解,最终时间会证明你辛勤的付出.下面是关于考研英语二的复习攻略,欢迎借鉴! ...

最新文章

  1. c++ primer plus 学习笔记
  2. react native与webview通信跳转页面报错:Cannot read property 'setNativeProps' of undefiend
  3. pythonxml解析拿到控件坐标_Python解析xml中dom元素的方法
  4. mysql时间模糊查询_mysql中那些根据时间查询的sql语句
  5. C++笔记-使用sprintf把各个类型转成char*(long long, doule,int)
  6. DE22 Using Laplace Transform to Solve ODEs with Discontinuous Inputs
  7. NullReferenceException
  8. 【BZOJ2839】集合计数【BZOJ3622】已经没有什么好害怕的了
  9. CSS3实现折角效果
  10. U盘快捷方程病毒 iexplore.vbs
  11. matlab 分水岭法,分水岭算法Matlab实现——三种方法 | 学步园
  12. 美国媒体称互联网不能成为低级趣味天堂
  13. try语句的基本用法
  14. Java 模拟斗地主发牌
  15. CSS3 3d旋转图片立方体案例演示
  16. PySpark线性回归与广义线性模型
  17. 重大要素改变中的机会选择包括_智慧树青年教师课堂教学比赛微课4答案
  18. 【新年祝福】散去2009分,祝大家新年快乐,祝所有朋友新的一年里万事如意。
  19. 【JavaSE 第八天】
  20. 【前端面试题】—53道常见NodeJS基础面试题(附答案)

热门文章

  1. 使用Wiredtiger恢复MongoDB中collection-x-xxx.wt文件数据
  2. LanSecS(堡垒主机)内控管理平台产品方案
  3. 全网通报:数模国赛作弊的后果
  4. 软件工程复习13:软件发布
  5. Python OpenCV 图片模糊操作 blur 与 medianBlur
  6. Python3爬取国家统计局官网2017年全国所有城市县镇数据
  7. 我眼中的大数据(一)
  8. 华为2288H V5服务器RAID配置
  9. 计算机在铁路中的应用论文800字,交通运输和交通论文,关于计算机信息网络系统在铁路交通运输管理中的应用相关参考文献资料-免费论文范文...
  10. 静态成员与静态成员函数