IndexDB简介
IndexedDB是一个事务型数据库系统,类似于基于SQL的RDBMS。 然而,不像RDBMS使用固定列表,IndexedDB是一个基于JavaScript的面向对象的数据库。 IndexedDB允许您存储和检索用键索引的对象;可以存储结构化克隆算法支持的任何对象。 您只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务。
- 阅读更多关于 IndexedDB背后的概念。
- 从使用IndexedDB指南的第一准则中学习异步使用IndexedDB。
- 联合使用IndexedDB储存离线数据和Service Workers储存离线资源,其简述请查看Service Workers制作离线PWAs。
注意: 正如大多数的web储存解决方案一样,IndexedDB也遵守同源策略。 因此当你在某个域名下操作储存数据的时候,你不能操作其他域名下的数据。
储存限制和回收标准
有许多Web技术在客户端(即本地磁盘)存储各种数据。IndexedDB是最常见的一个。浏览器计算分配给Web数据存储的空间以及达到该限制时要删除的内容的过程并不简单,并且在浏览器之间有所不同。浏览器存储限制和回收标准尝试解释这是如何工作的,至少在火狐的情况下是如此。 使用IndexedDB,你可以使用一个key作为索引进行存储或者获取数据。 你可以在事务(transaction)中完成对数据的修改。
indexedDB不使用结构化查询语言(SQL)。它通过索引(index)所产生的指针(cursor)来完成查询操作,从而使你可以迭代遍历到结果集合。如果你不熟悉NoSQL系统,可以参考维基百科相关文章。
名词解释
数据库(database)
一个信息库,通常包含一个或多个 object stores. 每个数据库必须包含以下内容:
名字(Name):它标识了一个特定源中的数据库,并且在数据库的整个生命周期内保持不变。 此名字可以为任意字符串值(包括空字符串)。
当前版本(version):当一个数据库首次创建时,它的 version 为1,除非另外指定. 每个数据库在任意时刻只能有一个 version。
对象仓库(object store)
数据在数据库中存储的方式, 数据以键值对形式被对象仓库永久持有。对象仓库中的的数据以 keys 升序排列。
每一个对象仓库在同一个数据库中必须有唯一的名字。对象存储可以有一个 key generator 和一个 key path。如果对象仓库有 key path,则使用 in-line keys; 否则使用 out-of-line keys。
关于对象仓库的详细文档,请参考 IDBObjectStore 或者 IDBObjectStoreSync。
数据库连接(database connection)
通过打开数据库创建的操作。一个给定的数据库可以同时拥有多个连接。
事务(transaction)
在一个特定的数据库上,一组具备原子性和持久性的数据访问和数据修改的操作。它是你与数据库交互的方式。并且,任何对于数据库中的数据读和修改的操作只能在事务中进行。
一个数据库连接可以拥有多个与之关联的事务,只要进行写操作事务的作用域不相互重合。事务的作用域在事务被创建时就被确定,指定事务能够进行交互的对象仓库(object store),作用域一旦被确定就会在整个生命周期中保持不变。举个例子,如果一个数据库连接已经有了一个进行写操作的事务,其作用域覆盖 flyingMonkey
对象仓库,你可以开启新的事务其作用于 unicornCentaur
和 unicornPegasus
对象仓库。对于读操作的事务,你可以同时拥有多个,即使他们有重叠的作用域。
事务被期望拥有较短的生命周期,所以浏览器会终止一个消耗时间过长的事务,为了释放存储资源,运行过久的事务会被锁定。你可以中断一个事务,来回滚事务中对数据库进行的操作。并且你甚至不需要等待事务开始或激活就可以中断它。
事务有三种模式:读写、只读和版本变更。创建和删除对象仓库(object store)的唯一方法就是通过调用版本变更事务。了解更多关于事务类型的内容,请参考 IndexedDB。
因为所有的事情都在事务中发生,所以它是 IndexedDB 中非常重要的一个概念。了解更多关于事务,尤其是关于它和版本控制的关联,查看 IDBTransaction 中的参考文档。关于同步接口的文档,查看 IDBTransactionSync。
使用教程
打开数据库
let db
const DBOpenRequest = window.indexedDB.open(dbName, version)
// 如果数据库打开失败
DBOpenRequest.onerror = () => {
console.log('数据库打开异常')
}
DBOpenRequest.onsuccess = () => {
// 存储数据结果
db = DBOpenRequest.result;
}
创建object store(数据表)信息
DBOpenRequest.onupgradeneeded = (event) => {
const db = event.target.result;
db.onerror = function() {
console.log('数据库打开失败');
};
// 创建一个数据库存储对象
const objectStore = db.createObjectStore(dbName, {
keyPath: 'id'
});
objectStore.createIndex('id', 'id', {
unique: true
})
};
这个示例中创建了in-line keys
的object store
,要求所有存储的数据中都要含有id字段,并且以此创建索引,方便后续针对此字段的查找。
createObjectStore
的第二个参数即可指定in-line keys
中的keyPath
objectStore.createIndex
的第一个参数是存储结构object store
的key值,第二个字段是存储结构中的key字段对应的要存储的数据对象中的属性值
也可以创建out-of-line keys
的object store
// 使用自动生成的递增数字作为键值
const objectStore = db.createObjectStore(dbName, { autoIncrement: true });
objectStore.createIndex('id', 'id', {
unique: true
})
增加/更新记录
有add
接口,在明确能区分是增加还是更新操作时,建议增加用add
接口与,更新用put
接口,以提高性能。
但是有些场景是无法区分是增加或者是更新操作的,譬如某个操作后需要更新数据,但是并不知道这条数据之前是否已经存在,那么都使用put
接口即可,put
接口在没有记录是会增加,存在记录时则更新
const transaction = this.db.transaction([dbName], "readwrite")
// 打开已经存储的数据对象
const objectStore = transaction.objectStore(dbName)
// 添加到数据对象中
const objectStoreRequest = objectStore.put(value) // 或者使用objectStore.add(value)
objectStoreRequest.onsuccess = () => {
resolve()
}
objectStoreRequest.onerror = (err) => {
console.error(`从数据库读取${key}异常`,err)
reject()
}
注意:如果创建的表为out-of-line keys
类型的object store
,那么put()
方法中的value不为单参数的“{}”对象形式,而是put(值,键)
的形式。
查询记录
查询记录需要使用cursor
, cursor
类似一个指针,在数据记录中一条条移动遍历出每条记录
let recordList = []
const objectStore = db.transaction(dbName).objectStore(dbName);
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
// 如果没有遍历完,继续下面的逻辑
if (cursor) {
recordList.push(cursor.value);
// 继续下一个游标项
cursor.continue();
// 如果全部遍历完毕
} else {
console.log('存储的数据为',JSON.stringify(recordList))
}
}
删除记录
const transaction = db.transaction([dbName], "readwrite")
// 打开已经存储的数据对象
const objectStore = transaction.objectStore(dbName)
// 添加到数据对象中
const objectStoreRequest = objectStore.delete(id)
objectStoreRequest.onsuccess = () => {
console.log(`删除${id}成功`)
}
objectStoreRequest.onerror = (err) => {
console.error(`从数据库删除${id}异常`, err)
}
参考资料
http://echizen.github.io/tech/2018/06-23-indexdb
教程及介绍
http://www.softwhy.com/article-10254-1.html
in-line key与out-in-line key实例
期待你的神评呦~