IndexedDB 是一种在用户浏览器中持久存储数据的方法。它允许您不考虑网络可用性,创建具有丰富查询能力的可离线 Web 应用程序。IndexedDB 对于存储大量数据的应用程序(例如借阅库中的 DVD 目录)和不需要持久 Internet 连接的应用程序(例如邮件客户端、待办事项列表或记事本)很有用。
关于本文档
本简介讨论了 IndexedDB 中的基本概念和术语。为您提供了概览并解释了关键概念。
您会发现以下非常有用的内容:
- 有关 IndexedDB 的设计和结构的概述,请参阅概览。
- 要了解有关 IndexedDB 术语的更多信息,请参阅定义部分。
- 有关如何使用 API 的详细教程,请参阅使用 IndexedDB。
- 有关 IndexedDB API 的参考文档,请参阅主要的 IndexedDB API 文章及其子页面,这些文章记录了 IndexedDB 使用的对象类型。
- 有关浏览器如何处理在后台存储数据的更多信息,请阅读浏览器存储限制和清理标准。
IndexedDB概况
使用IndexedDB,你可以使用一个key作为索引进行存储或者获取数据。 你可以在事务(transaction)中完成对数据的修改。和大多数web存储解决方案相同,indexedDB也遵从同源协议(same-origin policy). 所以你只能访问同域中存储的数据,而不能访问其他域的。
IndexedDB 是一种异步(asynchronous) API,异步API适用于大多数情况,包括Web Workers。因为在Web Workers上的使用,它过去也有一个同步(synchronous)的版本,但是因为缺少web社区的支持,它已经被从规范中移除了。
IndexedDB 过去有一个竞争规范—— WebSQL 数据库,但是W3C组织在2010年11月18日废弃了webSql。尽管两者都是存储的解决方案,但是他们提供的不是同样的功能。IndexedDB 和WebSQL的不同点在于WebSQL 是关系型数据库访问系统,IndexedDB 是索引表系统(key-value型)。
基本概念
如果你因为使用其他类型数据库有某些固定思维,那么你在使用IndexedDB的时候可能会感到困惑,所以请牢记以下重要的概念:
-
IndexedDB 数据库使用 key-value 键值对储存数据. values 数据可以是结构非常复杂的对象,key可以是对象自身的属性。你可以对对象的任何属性创建索引(index)以实现快速查询和列举排序。key可以是二进制对象。
-
IndexedDB 是事务模式的数据库. 任何操作都发生在事务(transaction)中。 IndexedDB API提供了索引(indexes)、表(tables)、指针(cursors)等等,但是所有这些必须是依赖于某种事务的。因此,你不能在事务外执行命令或者打开指针。事务(transaction)有生存周期,在生存周期以后使用它会报错。并且,事务(transaction)是自动提交的,不可以手动提交。
当用户在不同的标签页同时打开Web应用的两个实例时,这个事务模型就会非常有用。如果没有事务操作的支持,这两个实例就会互相影响对方的修改。如果你不熟悉数据库的事务模型,请参考数据库事务(维基百科)。 同时参考transaction文章中关于事务的定义部分。
-
The IndexedDB API 基本上是异步的。 IndexedDB的API不通过return语句返回数据,而是需要你提供一个回调函数来接受数据。执行API时,你不以同步(synchronous)方式对数据库进行“存储”和“读取”操作,而是向数据库发送一个操作“请求”。当操作完成时,数据库会以DOM事件的方式通知你,同时事件的类型会告诉你这个操作是否成功完成。这个过程听起来会有些复杂,但是里面是有明智的原因的。这个和XMLHttpRequest请求是类似的
-
IndexedDB数据库“请求”无处不在。 我们上边提到,数据库“请求”负责接受成功或失败的DOM事件。每一个“请求”都包含
onsuccess
和onerror事件
属性,同时你还对“事件”调用addEventListener()和removeEventListener()。“请求”还包括readyState,
result
和errorCode属性,用来表示“请求”的状态。result属性尤其神奇,他可以根据“请求”生成的方式变成不同的东西,例如:
IDBCursor实例、刚插入数据库的数值对应的键值(key)等。
-
IndexedDB在结果准备好之后通过DOM事件通知用户。 DOM事件总是有一个类型(
type
)属性(在IndexedDB中,该属性通常设置为success
或error
)。DOM事件还有一个目标(target
)属性,用来告诉事件是被谁触发的。通常情况下,目标(target
)属性是数据库操作生成的IDBRequest。成功(success)事件不弹出提示并且不能撤销,错误(error)事件会弹出提示且可以撤销。这一点是非常重要的,因为除非错误事件被撤销,否则他们会终止所在的任何事务。 -
IndexedDB是面向对象的。indexedDB不是用二维表来表示集合的关系型数据库。这一点非常重要,将影响你设计和建立你的应用程序。
传统的关系型数据库,你需要用到二维表来存储数据集合(每一行代表一个数据,每一列代表一个属性),indexedDB有所不同,它要求你为一种数据创建一个对象仓库(object Store),只要这种数据是一个JavaScript对象即可。每个对象仓库都有一个索引(index)集合以方便查询和迭代遍历。如果你不熟悉面向对象的数据库管理系统,可以参考维基百科有关对象数据库的内容
-
indexedDB不使用结构化查询语言(SQL)。它通过索引(index)所产生的指针(cursor)来完成查询操作,从而使你可以迭代遍历到结果集合。如果你不熟悉NoSQL系统,可以参考维基百科相关文章。
-
IndexedDB遵循同源(same-origin)策略 “源”指脚本所在文档URL的域名、应用层协议和端口。每一个“源”都有与其相关联的数据库。在同一个“源”内的所有数据库都有唯一、可区别的名称。
IndexedDB的安全机制避免应用访问非同“源”的数据。例如,http://www.example.com/app/的应用或页面可以访问http://www.example.com/dir/的数据,因为他们同“源”。但是它们不能访问http://www.example.com:8080/dir/(不同端口)或https://www.example.com/dir/(不同协议)的数据,因为他们不同“源”。
-
注意:第三方窗口上下文(例如HTML元素iframe)可以访问它所嵌入的网页的IndexedDB,除非浏览器被设置为never accept third party cookies (see bug 1147821.)
名词解释
本节定义并解释了IndexedDB API中所使用的术语
数据库
- 数据库(database)
- 一个信息库,通常包含一个或多个 object stores. 每个数据库必须包含以下内容:
-
- 名字(Name)。它标识了一个特定源中的数据库,并且在数据库的整个生命周期内保持不变。 此名字可以为任意字符串值(包括空字符串)。
- 当前版本(version)。当一个数据库首次创建时,它的 version 为1,除非另外指定. 每个数据库在任意时刻只能有一个 version。
- 持久性(durable)
- 在 Firefox 中,IndexedDB 是持久的,也就是说在一个读写事务中,一旦
IDBTransaction.oncomplete
事件被触发,就代表着数据已经确保被写入磁盘中了。 - 从 Firfox 40 起,IndexedDB 事务放松了对持久性的保证以提高性能(参见 Bug1112702),这与其他支持 IndexedDB 的浏览器的处理方式相同。在这种情况下,当操作系统被告知去写入数据后
complete
事件便被触发,但此时数据可能还没有真正的写入磁盘。事件触发因此变得更快,但这样会有极小的机会发生以下情况:如果操作系统崩溃或在数据被写入磁盘前断电,那么整个事务都将丢失。由于这种灾难事件是罕见的,大多数使用者并不需要过分担心。 - 对象仓库(object store)
-
数据在数据库中存储的方式, 数据以键值对形式被对象仓库永久持有。对象仓库中的的数据以 keys 升序排列。
每一个对象仓库在同一个数据库中必须有唯一的名字。对象存储可以有一个 key generator 和一个 key path。如果对象仓库有 key path,则使用 in-line keys; 否则使用 out-of-line keys。
关于对象仓库的详细文档,请参考 IDBObjectStore 或者 IDBObjectStoreSync。
- 版本(version)
- 当第一次创建一个数据库,它的版本为整型1。每个数据库依次有一个版本号; 一个数据库不能同时存在多个版本号。改变版本的唯一方法是通过一个比当前版本号更高的值去打开数据库。这会开启一个
VERSION_CHANGE
事务并且触发upgradeneeded
事件。只有在该事件的处理函数中才能更新数据库模式。 - 注意:这里的描述以最新规范为准,这些规范可能只在最新的浏览器中实现了。老旧的浏览器实现了现在已弃用和移除的
IDBDataBase.setVersion()
方法。 - 数据库连接(database connection)
- 通过打开数据库创建的操作。一个给定的数据库可以同时拥有多个连接。
- 事务(transaction)
- 在一个特定的数据库上,一组具备原子性和持久性的数据访问和数据修改的操作。它是你与数据库交互的方式。并且,任何对于数据库中的数据读和修改的操作只能在事务中进行。
-
一个数据库连接可以拥有多个与之关联的事务,只要进行写操作事务的作用域不相互重合。事务的作用域在事务被创建时就被确定,指定事务能够进行交互的对象仓库(object store),作用域一旦被确定就会在整个生命周期中保持不变。举个例子,如果一个数据库连接已经有了一个进行写操作的事务,其作用域覆盖
flyingMonkey
对象仓库,你可以开启新的事务其作用于unicornCentaur
和unicornPegasus
对象仓库。对于读操作的事务,你可以同时拥有多个,即使他们有重叠的作用域。事务被期望拥有较短的生命周期,所以浏览器会终止一个消耗时间过长的事务,为了释放存储资源,运行过久的事务会被锁定。你可以中断一个事务,来回滚事务中对数据库进行的操作。并且你甚至不需要等待事务开始或激活就可以中断它。
事务有三种模式:读写、只读和版本变更。创建和删除对象仓库(object store)的唯一方法就是通过调用版本变更事务。了解更多关于事务类型的内容,请参考 IndexedDB。
因为所有的事情都在事务中发生,所以它是 IndexedDB 中非常重要的一个概念。了解更多关于事务,尤其是关于它和版本控制的关联,查看 IDBTransaction 中的参考文档。关于同步接口的文档,查看 IDBTransactionSync。
- 请求(request)
- 在数据库上进行读写操作完成后的操作。每一个请求代表一个读或写操作。
- 索引(index)
-
一个对象仓库,专门用来查找另一个对象仓库(object store)中的记录,其中被查找的对象仓库被称为引用对象仓库。索引(index)是一个稳定的键值对(key-value)存储,其记录中的值(value)是引用对象仓库记录中的键(key)。当引用对象仓库中的记录新增、更新或删除时,索引中的记录会自动的进行粒子性增加。索引中的每一条记录只能指向引用对象仓库中的一条记录,但多个索引可以引用同一个对象仓库。当对象仓库发生改变时,所有引用该对象仓库的引用均会自动更新。
可选地,你也可以适用键(key)再对象仓库中查找记录。
了解更多关于如何适用索引,查看使用 IndexedDB。index 的参考文档查看 IDBKeyRange。
键和值
- 键(key)
- 在对象仓库中阻止和检索被存储起来的值的数据值。数据仓库的键来源于以下三个方式之一:键生成器、键路径和显式指定的值。键必须是一种能够比较大小的数据类型。在同一个对象仓库中每条记录必须有一个独一无二的键,所以你不能在同一个对象仓库中为多个记录设置同样的键。
-
键可以是以下数据类型:字符串、日期、浮点和数组。对于数组,键的取值可以从空数组到无穷。并且你可以使用嵌套数组。注意,在 Firefox 11 之前的版本键只接受字符串和整形。
可选地,你也可以通过索引(index)来查找记录。
- 键生成器(key generator)
- 一种生成有序键的机制。如果一个对象仓库并不具备一个键生成器,那么应用程序必须为被存储的记录提供键。生成器在仓库之间并不共享。它更多的是浏览器的实现细节,因为在 Web 开发中你并不会真正的去创建或访问键生成器。
- 内键(in-line key)
- 作为存储值一部分的键。内键由键路径(key path)查找。内键由生成器生成。当内键生成后,它会被键路径存储在值中,它也可以被当作键使用。
- 外键(out-of-line key)
- 与值分开存储的键。
- 键路径(key path)
- 指定浏览器如何从对象仓库或索引存储的值中提取键。一个合法的键路径可以是以下形式:一个空字符串,一个 JavasScript 标识符,或由句点分割的多个 JavaScript 标识符。但不能包括空格。
- 值(value)
- 每条记录包含一个值,该值可以包含任何 JavaScript 表达式,包括:布尔、数字、字符串、日期、对象、数组、正则、未定义和 null。
-
对于对象和数组,它们的属性和值也可以是任意合法的值。
范围和作用域
- 作用域(scope)
- 事务所作用的一组对象仓库或索引。只读事务的作用域可以相互重叠并同时执行操作。但写操作事务的作用域不可以相互重叠。但你仍然可以同时开启多个拥有相同作用域的事务,只要保证他们的操作不会同时执行。
- 游标(cursor)
- 在键的某个范围内迭代查询多条记录的机制。游标有一个指向正在被迭代的对象仓库或索引的源。它处于该范围内的一个位置,并按照键的顺序正向或逆向的移动。有关游标的参考文档,查看 IDBCursor 或 IDBCursorSync。
- 键范围(key range)
- 用做键的数据类型上的连续的间隔。使用键或键的某个范围可以从对象仓库和索引中读取记录。你可以通过上限和下限设置和筛选范围。比如,你可以遍历 x 和 y 之间所有的键值。
- 有关键范围的参考文档,查看 IDBKeyRange.
局限性
以下情况不适合使用IndexedDB
- 全球多种语言混合存储。国际化支持不好。需要自己处理。
- 和服务器端数据库同步。你得自己写同步代码。
- 全文搜索。IndexedDB 接口没有类似 SQL 语句中
LIKE
的功能。
注意,在以下情况下,数据库可能被清除:
- 用户请求清除数据。
- 浏览器处于隐私模式。最后退出浏览器的时候,数据会被清除。
- 硬盘等存储设备的容量到限。
- 数据损坏。
- 进行与特性不兼容的操作。
确切的环境和浏览器特性会随着时间改变,但浏览器厂商通常会遵循尽最大努力保留数据的理念。
下一步
查看如何使用的文档: Using IndexedDB.