【JavaScript 漫游】【043】IndexedDB API 总结
文章简介
本篇文章为【JavaScript 漫游】专栏的第 043 篇文章,对浏览器模型中的 IndexedDB API 进行了总结。
概述
随着浏览器的功能不断增强,越来越多的网站开始考虑,将大量数据储存在客户端,这样可以减少从服务器获取数据,直接从本地获取数据。
现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过 4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。
通俗地说,IndexedDB 就是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB 允许储存大量数据,提供查找接口,还能建立索引。这些都是 LocalStorage 所不具备的。就数据库类型而言,IndexedDB 不属于关系型数据库(不支持 SQL 查询语句),更接近 NoSQL 数据库。
IndexedDB 具有以下特点。
- 键值对储存。IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以“键值对”的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误
- 异步。IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
- 支持事务。IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
- 同源限制。IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
- 储存空间大。 IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
- 支持二进制储存。 IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
基本概念
IndexedDB 是一个比较复杂的 API,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API,就是学习它的各种对象接口。
- 数据库:IDBDatabase 对象
- 对象仓库:IDBObjectStore 对象
- 索引: IDBIndex 对象
- 事务: IDBTransaction 对象
- 操作请求:IDBRequest 对象
- 指针: IDBCursor 对象
- 主键集合:IDBKeyRange 对象
数据库
数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。
IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。
对象仓库
每个数据库包含若干个对象仓库(object store)。它类似于关系型数据库的表格。
数据记录
对象仓库保存的是数据记录。每条记录类似于关系型数据库的行,但是只有主键和数据体两部分。主键用来建立默认的索引,必须是不同的,否则会报错。主键可以是数据记录里面的一个属性,也可以指定为一个递增的整数编号。
{ id: 1, text: 'foo' }
上面的对象中,id
属性可以当作主键。
数据体可以是任意数据类型,不限于对象。
索引
为了加速数据的检索,可以在对象仓库里面,为不同的属性建立索引。
事务
数据记录的读写和删改,都要通过事务完成。事务对象提供 error
、abort
和 complete
三个事件,用来监听操作结果。
操作流程
打开数据库
使用 IndexedDb.open()
打开数据库。
// databaseName: 数据库名;version: 数据库版本,默认 1
var request = window.indexedDB.open(databaseName, version);
该方法返回一个 IDBRequest 对象。这个对象通过三种事件 error
、success
、upgradeneeded
,处理打开数据库的操作结果。它们分别表示失败、成功和数据库升级。
var db; // 数据库对象
request.onerror = function (event) {
console.log('数据库打开报错');
};
request.onsuccess = function (event) {
db = request.result;
console.log('数据库打开成功');
};
// 如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件 `upgradeneeded`
request.onupgradeneeded = function (event) {
db = event.target.result;
}
新建数据库
新建数据库与打开数据库是同一个操作。如果指定的数据库不存在,就会新建。不同之处在于,后续的操作主要在 upgradeneeded
事件的监听函数里面完成,因为这时版本从无到有,所以会触发这个事件。
通常,新建数据库以后,第一件事是新建对象仓库(即新建表)。
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore = db.createObjectStore('person', { keyPath: 'id' });
}
更好的写法是先判断一下,这张表格是否存在,如果不存在再新建。
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('person')) {
objectStore = db.createObjectStore('person', { keyPath: 'id' });
}
}
主键(key)是默认建立索引的属性。比如,数据记录是 { id: 1, name: '张三'}
,那么 id
属性可以作为主键。主键也可以指定为下一层对象的属性,比如 { foo: { bar: 'baz' }}
的 foo.bar
也可以指定为主键。
如果数据记录里面没有合适作为主键的属性,那么可以让 IndexedDB 自动生成主键。
var objectStore = db.createObjectStore(
'person',
{ autoIncrement: true }
);
新建对象仓库以后,下一步可以新建索引。
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore = db.createObjectStore('person', { keyPath: 'id' });
objectStore.createIndex('name', 'name', { unique: false });
objectStore.createIndex('email', 'email', { unique: true });
}
新增数据
新增数据指的是向对象仓库写入数据记录。这需要通过事务完成。
function add() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.add({ id: 1, name: '张三', age: 24, email: 'zhangsan@example.com' });
request.onsuccess = function (event) {
console.log('数据写入成功');
};
request.onerror = function (event) {
console.log('数据写入失败');
}
}
add();
读取数据
function read() {
var transaction = db.transaction(['person']);
var objectStore = transaction.objectStore('person');
var request = objectStore.get(1);
request.onerror = function(event) {
console.log('事务失败');
};
request.onsuccess = function( event) {
if (request.result) {
console.log('Name: ' + request.result.name);
console.log('Age: ' + request.result.age);
console.log('Email: ' + request.result.email);
} else {
console.log('未获得数据记录');
}
};
}
read();
遍历数据
遍历数据表格的所有记录,要使用指针对象 IDBCursor。
function readAll() {
var objectStore = db.transaction('person').objectStore('person');
objectStore.openCursor().onsuccess = function (event) {
var cussor = event.target.result;
if (cursor) {
console.log('Id: ' + cursor.key);
console.log('Name: ' + cursor.value.name);
console.log('Age: ' + cursor.value.age);
console.log('Email: ' + cursor.value.email);
cursor.continue();
} else {
console.log('没有更多数据了!')
}
};
}
readAll();
更新数据
更新数据要使用 IDBOjbect.put()
。
fucntion update() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });
request.onsuccess = function(event) {
console.log('数据更新成功');
};
request.onerror = function(event) {
console.log('数据更新失败');
}
}
update();
删除数据
IDBObjectStore.delete()
用于删除记录。
function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1);
request.onsuccess = function (event) {
console.log('数据删除成功');
}
}
remove();
使用索引
索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
假定新建表格的时候,对 name
字段建立了索引。
objectStore.createIndex('name', 'name', { unique: false });
现在,就可以从 name
找到对应的数据记录了。
var transaction = db.transaction(['person'], 'readonly');
var store = transaction.objectStore('person');
var index = store.index('name');
var request = index.get('李四');
request.onsuccess = function (e) {
var result = e.target.result;
if (result) {
// ...
} else {
// ...
}
}
indexedDB 对象
浏览器原生提供 indexedDB
对象,作为开发者的操作接口。
indexedDB.open()
用于打开数据库。这是一个异步操作,但是会立刻返回一个 IDBOpenDBRequest 对象。
var openRequest = window.indexedDB.open('test', 1);
打开数据库是异步操作,通过各种事件通知客户端。下面是有可能触发的 4 种事件。
- success:打开成功
- error:打开失败
- upgradeneeded:第一次打开该数据库,或者数据库版本发生变化
- blocked:上一次的数据库连接还未关闭
第一次打开数据库时,会先触发 upgradeneeded
事件,然后触发 upgradeneeded
事件,然后触发 success
事件。
根据不同的需要,对上面 4 种事件监听函数。
var openRequest = indexedDB.open('test', 1);
var db;
openRequest.onupgradeneeded = function (e) {
console.log('Upgrading...');
}
openRequest.onsuccess = function (e) {
console.log('Success!');
db = openRequest.result;
}
openRequest.onerror = function (e) {
console.log('Error');
console.log(e);
}
两个注意点。首先,open()
返回的是一个对象(IDBOpenRequest),监听函数就定义在这个对象上面。其次,success
事件发生后,从 openRequest.result
属性可以拿到已经打开的 IndexedDB
数据库对象。
indexedDB.deleteDatabase()
用于删除一个数据库,参数为数据库的名字。它会立刻返回一个 IDBOpenDBRequest
对象,然后对数据库执行异步删除。删除操作的结果会通过事件通知,IDBOpenRequest
对象可以监听以下事件。
success
:删除成功error
:删除报错
var DBDeleteRequest = window.indexedDB.deleteDatabase('demo');
DBDeleteRequest.onerror = function (event) {
console.log('Error');
};
DBDeleteRequest.onsuccess = function (event) {
console.log('success');
};
调用 deleteDatabase()
以后,当前数据库的其他已经打开的连接都会接收到 versionChange
事件。
indexedDB.cmp()
比较两个值是否为 indexedDB 的相同的主键。它返回一个整数,表示比较的结果:0
表示相同,1
表示第一个主键大于第二个主键,-1
表示第一个主键小于第二个主键。
window.indexedDB.com(1, 2); // -1
注意,这个方法不能用来比较任意的 JavaScript 值。如果参数是布尔值或对象,它会报错。
window.indexedDB.cmp(1, true) // 报错
window.indexedDB.cmp({}, {}) // 报错
IDBRequest 对象
IDBRequest 对象表示打开的数据库连接,indexedDB.open()
和 indexedDB.deleteDatabase()
会返回这个对象。数据库的操作都是通过这个对象完成的。
这个对象的所有操作都是异步操作,要通过 readyState
属性判断是否完成,如果为 pending
就表示操作正在进行,如果为done
就表示操作完成,可能成功也可能失败。
操作完成以后,触发 success
事件或 error
事件,这时可以通过 result
属性和 error
属性拿到操作结果。如果在 pending
阶段,就去读取这两个属性,是会报错的。
IDBRequest 对象有以下属性。
IDBRequest.readyState
:等于pending
表示操作正在进行,等于done
表示操作正在完成IDBRequest.result
:返回请求的结果。如果请求失败、结果不可用,读取该属性会报错IDBRequest.error
:请求失败时,返回错误对象IDBRequest.source
:返回请求的来源(比如索引对象或 ObjectStore)IDBRequest.transaction
:返回当前请求正在进行的事务,如果不包含事务,返回null
IDBRequest.onsuccess
:指定success
事件的监听函数IDBRequest.onerror
:指定error
事件的监听函数
IDBOpenDBRequest 对象继承了 IDBRequest 对象,提供了两个额外的事件监听属性。
IDBOpenDBRequest.onblocked
:指定blocked
事件(upgradeneeded
事件触发时,数据库仍然在使用)的监听函数IDBOpenDBRequest.onupgradeneeded
:upgradeneeded
事件的监听函数
IDBDatabase 对象
打开数据成功以后,可以从 IDBOpenDBRequest
对象的 result
属性上面,拿到一个 IDBDatabase
对象,它表示连接的数据库。后面对数据库的操作,都通过这个对象完成。
var db;
var DBOpenRequest = window.indexedDB.open('demo', 1);
DBOpenRequest.onerror = function (event) {
console.log('error');
};
DBOpenRequest.onsuccess = function (event) {
db = DBOpenRequest.result;
// ...
};
IDBDatabase 对象有以下属性。
IDBDatabase.name
:数据库名IDBDatabase.version
:数据库版本,第一次创建的时候,该属性为空字符串IDBDatabase.objectStoreNames
:DOMStringList 对象(字符串的集合),包含当前数据的所有 object store 的名字IDBDatabase.onabort
:指定 abort 事件(事务中止)的监听函数IDBDatabase.onclose
:指定 clost 事件(数据库意外关闭)的监听函数IDBDatabase.onerror
:指定 error 事件(访问数据库失败)的监听函数IDBDatabase.onversionchange
:数据库版本变化时触发(发生upgradeneeded
事件,或调用indexedDB.deleteDatabase()
)
if (!db.objectStoreNames.contains('firstOS')) {
db.createObjectStore('firstOS');
}
IDBDatabase 对象有以下方法。
IDBDatabase.close()
:关闭数据库连接,实际会等所有事务完成后再关闭IDBDatabase.createObjectStore()
:创建存放数据的对象仓库,类似于传统关系型数据库的表格,返回一个 IDBObjectStore 对象。该方法只能在versionchange
事件监听函数中调用IDBDatabase.deleteObjectStore()
:删除指定的对象仓库。该方法只能在versionchange
事件监听函数中调用IDBDatabase.transaction()
:返回一个 IDBTransaction 事务对象
var request = window.indexedDB.open('demo', 2);
request.onupgradeneeded = function (event) {
var db = event.target.result;
db.onerror = function (event) {
console.log('error');
};
var objectStore = db.createObjectStore('items');
// ...
};
var dbName = 'sampleDB';
var dbVersion = 2;
var request = indexedDB.open(dbName, dbVersion);
request.onupgradeneeded = function (e) {
var db = request.result;
if (e.oldVersion < 1) {
db.createObjectStore('store1');
}
if (e.oldVersion < 2) {
db.deleteObjectStore('store1');
db.createObjectStore('store2');
}
// ...
};
var t = db.transaction(['items'], 'readwrite');
第一个参数是一个数组,里面是所涉及的对象仓库,通常是只有一个;第二个参数是一个表示操作类型的字符串。操作类型只有两种:readonly
和 readwrite
。
IDBObjectStore 对象
IDBObjectStore 对象对应一个对象仓库(object store)。IDBDatabase.createObjectStore()
返回的就是一个 IDBObjectStore 对象。
IDBDatabase 对象的 transaction()
返回 IDBObjectStore 对象,因此可以采用下面的链式写法。
db.transaction(['test'], 'readonly')
.objectStore('test')
.get(X)
.onsuccess = function (e) {};
IDBObjectStore 对象有以下属性。
IDBObjectStore.indexNames
:返回一个类似数组的对象(DOMStringList),包含了当前对象仓库的所有索引IDBObjectStore.keyPath
:返回当前对象仓库的主键IDBObjectStore.name
:返回当前对象仓库的名称IDBObjectStore.transaction
:返回当前对象仓库所属的事务对象IDBObjectStore.autoIncrement
:布尔值,表示主键是否会自动递增
IDBObjectStore 对象有以下方法。
IDBObjectStore.add()
用于向对象仓库添加数据,返回一个 IDBRequest 对象。该方法只用于添加数据,如果主键相同会报错,因此更新数据必须使用 put()
。
objectStore.add(value, key);
该方法接受两个参数,第一个参数是键值,第二个参数是主键,该参数可选,如果省略默认为 null
。
创建事务以后,就可以获取对象仓库,然后使用 add()
往里面添加数据了。
var db;
var DBOpenRequest = window.indexedDB.open('demo', 1);
DBOpenRequest.onsuccess = function (event) {
db = DBOpenRequest.result;
var transaction = db.transaction(['items'], 'readwrite');
transaction.oncomplete = function(event) {
console.log('transaction success');
};
transaction.onerror = function(event) {
console.log('transaction error: ' + transaction.error);
};
var objectStore = transaction.objectStore('items');
var objectStoreRequest = objectStore.add({ foo: 1 });
objectStoreRequest.onsuccess = function (event) {
console.log('add data success');
};
};
IDBObjectStore.put()
用于更新某个主键对应的数据记录,如果对应的键值不存在,则插入一条新的记录。该方法返回一个 IDBRequest 对象。
objectStore.put(item, key);
该方法接受两个参数,第一个参数为新数据,第二个参数为主键,该参数可选,且只在自动递增时才有必要提供,因为那时主键不包含在数据值里面。
IDBObjectStore.put()
用于更新某个主键对应的数据记录,如果对应的键值不存在,则插入一条新的记录。该方法返回一个 IDBRequest 对象。
objectStore.put(item, key)
IDBObjectStore.clear()
删除当前对象仓库的所有记录,并返回一个 IDBRequest 对象。
objectStore.clear()
IDBObjectStore.delete()
用于删除指定主键的记录。该方法返回一个 IDBRequest 对象。
objectStore.delete(Key)
IDBObjectStore.count()
用于计算记录的数量。返回一个 IDBRequest 对象。
IDBObjectStore.count(key);
不带参数时,该方法返回当前对象仓库的所有记录数量。如果主键或 IDBKeyRange 对象作为参数,则返回对应的记录数量。
IDBObjectStore.getKey()
用于获取主键,返回一个 IDBRequest 对象。
objectStore.getKey(key)
参数可以是主键值或 IDBKeyRange 对象。
IDBObjectStore.get()
用于获取主键对应的数据记录,返回一个 IDBRequest 对象。
objectStore.get(key);
IDBObjectStore.getAll()
用于获取对象仓库的记录,返回一个 IDBRequest 对象。
// 获取所有记录
objectStore.getAll();
// 获取所有符合指定主键或 IDBKeyRange 的记录
objectStore.getAll(query);
// 指定获取记录的数量
objectStore.getAll(query, count);
IDBObjectStore.getAllKeys()
用于获取所有符合条件的主键,该方法返回一个 IDBRequest 对象。
// 获取所有记录的主键
objectStore.getAllKeys();
// 获取所有符合条件的主键
objectStore.getAllKeys(query);
// 指定获取主键的数量
objectStore.getAllKeys(query, count);
IDBObjectStore.index()
返回指定名称的索引对象 IDBIndex。
objectStore.index(name);
有了索引以后,就可以针对索引所在的属性读取数据。
var t = db.transaction(['people'], 'readonly');
var store = t.objectStore('people');
var index = store.index('name');
var request = index.get('foo');
IDBObjectStore.createIndex()
用于新建当前数据库的一个索引。该方法只能在 VersionChange
监听函数里面调用。
objectStore.createIndex(indexName, keyPath, objectParameters);
- indexName:索引名
- keyPath:主键
- objectParameters:配置对象(可选)
第三个参数可以配置以下属性。
- unique:如果设为
true
,将不允许重复的值 - multiEntry:如果设为
true
,对于有多个值的主键数组,每个值将在索引里面新建一个条目,否则主键数组对应一个条目
假定对象仓库中的数据记录都是如下的 person
类型
var person = {
name: name,
email: email,
created: new Date()
};
可以指定这个对象的某个属性来建立索引。
var store = db.createObjectStore('people', { autoIncrement: true });
store.createIndex('name', 'name', { unique: false });
store.createIndex('email', 'email', { unique: true });
IDBObjectStore.deleteIndex()
用于删除指定的索引。该方法只能在 VersionChange
监听函数里面调用。
objectStore.deleteIndex(indexName);
IDBObjectStore.openCursor()
用于获取一个指针对象。
IDBObjectStore.openCursor()
指针对象可以用来遍历数据。该对象也是异步的,有自己的 success
和 error
事件,可以对它们指定监听函数。
var t = db.transaction(['test'], 'readonly');
var store = t.objectStore('test');
var cursor = store.openCursor();
cursor.onsuccess = function (event) {
var res = event.target.result;
if (res) {
console.log('Key', res.key);
console.log('Data', res.value);
res.continue();
}
}
openCursor()
的第一个参数是主键值,或者一个 IDBKeyRange 对象。如果指定该参数,将只处理包含指定主键的记录;如果省略,将处理所有的记录。该方法还可以接受第二个参数,表示遍历方向,默认值为 next
,其他可能的值为 prev
、nextunique
和 prevunique
。后两个值表示如果遇到重复值,会自动跳过。
IDBObjectStore.openKeyCursor()
用于获取一个主键指针对象。
IDBObjectStore.openKeyCursor()
IDBTransaction 对象
IDBTransaction 对象用来异步操作数据库事务,所有的读写操作都要通过这个对象进行。
IDBDatabase.transaction()
返回的就是一个 IDBTransaction 对象。
var db;
var DBOpenRequest = window.indexedDB.open('demo', 1);
DBOpenRequest.onsuccess = function(event) {
db = DBOpenRequest.result;
var transaction = db.transaction(['demo'], 'readwrite');
transaction.oncomplete = function(event) {
cnosole.log('transaction success');
};
transaction.onerror = function(event) {
console.log('transaction error: ' + transaction.error);
};
var objectStore = transaction.objectStore('demo');
var objectStoreRequest = objectStore.add({ foo: 1 });
objectStoreRequest.onsuccess = function(event) {
console.log('add data success');
};
};
事务的执行顺序是按照创建的顺序,而不是发出请求的顺序。
var trans1 = db.transaction('foo', 'readwrite');
var trans2 = db.transaction('foo', 'readwrite');
var objectStore2 = trans2.objectStore('foo')
var objectStore1 = trans1.objectStore('foo')
objectStore2.put('2', 'key');
objectStore1.put('1', 'key');
注意,事务有可能失败,只有监听到事务的 complete
事件,才能保证事务操作成功。
IDBTransaction 对象有以下属性。
IDBTransaction.db
:返回当前事务所在的数据库对象 IDBDatabaseIDBTransaction.error
:返回当前事务的错误。如果事务么有结束,或者事务成功结束,或者被手动终止,该方法返回null
IDBTransaction.mode
:返回当前事务的模式,默认是readonly
(只读),另一个值是readwrite
IDBTransaction.objectStoreNames
:返回一个类似数组的对象 DOMStringList,成员是当前事务涉及的对象仓库的名字IDBTransaction.onabort
:指定abort
事件(事务中断)的监听函数IDBTransaction.oncomplete
:指定complete
事件(事务成功)的监听函数IDBTransaction.onerror
:指定error事件(事务失败)的监听函数
IDBTransaction 对象有以下方法。
IDBTransaction.abort()
:终止当前事务,回滚所有已经进行的变更IDBTransaction.objectStore(name)
:返回指定名称的对象仓库 IDBObjectStore
IDBIndex 对象
IDBIndex 对象代表数据库的索引,通过这个对象可以获取数据库里面的记录。数据记录的主键默认就是带有索引,IDBIndex 对象主要用于通过除主键以外的其他键,建立索引获取对象。
IDBIndex 是持久性的键值对存储。只要插入、更新或删除数据记录,引用的对象库中的记录,索引就会自动更新。
IDBObjectStore.index()
方法可以获取 IDBIndex 对象。
var transaction = db.transaction(['contactsList'], 'readonly');
var objectStore = transaction.objectStore('contactsList');
var myIndex = objectStore.index('lName');
myIndex.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
var tableRow = document.createElement('tr');
tableRow.innerHTML = '<td>' + cursor.value.id + '</td>'
+ '<td>' + cursor.value.lName + '</td>'
+ '<td>' + cursor.value.fName + '</td>'
+ '<td>' + cursor.value.jTitle + '</td>'
+ '<td>' + cursor.value.company + '</td>'
+ '<td>' + cursor.value.eMail + '</td>'
+ '<td>' + cursor.value.phone + '</td>'
+ '<td>' + cursor.value.age + '</td>';
tableEntry.appendChild(tableRow);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};
IDBIndex 对象有以下属性。
IDBIndex.name
:字符串,索引的名称IDBIndex.objectStore
:索引所在的对象仓库IDBIndex.keyPath
:索引的主键IDBIndex.multiEntry
:布尔值,针对keyPath
为数组的情况,如果设为true
,创建数组时,每个数组成员都会有一个条目,否则每个数组都只有一个条目IDBIndex.unique
:布尔值,表示创建索引时是否允许相同的主键
IDBIndex 对象有以下方法,它们都是异步的,立即返回的都是一个 IDBRequest 对象
IDBIndex.count()
:用来获取记录的数量。它可以接受主键或 IDBKeyRange 对象作为参数,这时只返回符合主键的记录数量,否则返回所有记录的数量IDBIndex.get(key)
:用来获取符合指定主键的数据记录IDBIndex.getKey(key)
:用来获取指定的主键IDBIndex.getAll()
:用来获取所有的数据记录。它可以接受两个参数,都是可选的,第一个参数用来指定主键,第二个参数用来指定返回记录的数量。如果省略这两个参数,则返回所有记录。由于获取成功时,浏览器必须生成所有对象,所以对性能有影响。如果数据集比较大,建议使用 IDBCursor 对象IDBIndex.getAllKeys()
:该方法与IDBIndex.getAll()
方法相似,区别是获取所有主键IDBIndex.openCursor()
:用来获取一个 IDBCursor 对象,用来遍历索引里面的所有条目IDBIndex.openCursor()
:用来获取一个 IDBCursor 对象,用来遍历索引里面的所有条目
IDBCursor 对象
IDBCursor 对象代表指针对象,用来遍历数据仓库(IDBObjectStore)或索引(IDBIndex)的记录。
IDBCursor 对象一般通过 IDBObjectStore.openCursor()
方法获得。
var transaction = db.transaction(['rushAlbumList'], 'readonly');
var objectStore = transaction.objectStore('rushAlbumList');
objectStore.openCursor(null, 'next').onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var listItem = document.createElement('li');
listItem.innerHTML = cursor.value.albumTitle + ', ' + cursor.value.year;
list.appendChild(listItem);
console.log(cursor.source);
cursor.continue();
} else {
console.log('Entries all displayed.');
}
};
};
IDBCursor 对象的属性。
IDBCursor.source
:返回正在遍历的对象仓库或索引IDBCursor.direction
:字符串,表示指针遍历的方向。共有四个可能的值:next(从头开始向后遍历)、nextunique(从头开始向后遍历,重复的值只遍历一次)、prev(从尾部开始向前遍历)、prevunique(从尾部开始向前遍历,重复的值只遍历一次)。该属性通过IDBObjectStore.openCursor()
方法的第二个参数指定,一旦指定就不能改变了IDBCursor.key
:返回当前记录的主键IDBCursor.value
:返回当前记录的数据值IDBCursor.primaryKey
:返回当前记录的主键。对于数据仓库(objectStore)来说,这个属性等同于 IDBCursor.key;对于索引,IDBCursor.key 返回索引的位置值,该属性返回数据记录的主键
IDBCursor 对象有如下方法。
IDBCursor.advance(n)
:指针向前移动 n 个位置IDBCursor.continue()
:指针向前移动一个位置。它可以接受一个主键作为参数,这时会跳转到这个主键IDBCursor.continuePrimaryKey()
:该方法需要两个参数,第一个是key
,第二个是primaryKey
,将指针移到符合这两个参数的位置IDBCursor.delete()
:用来删除当前位置的记录,返回一个 IDBRequest 对象。该方法不会改变指针的位置IDBCursor.update()
:用来更新当前位置的记录,返回一个 IDBRequest 对象。它的参数是要写入数据库的新的值
IDBKeyRange 对象
IDBKeyRange 对象代表数据仓库(object store)里面的一组主键。根据这组主键,可以获取数据仓库或索引里面的一组记录。
IDBKeyRange 可以只包含一个值,也可以指定上限和下限。它有四个静态方法,用来指定主键的范围。
IDBKeyRange.lowerBound()
:指定下限IDBKeyRange.upperBound()
:指定上限IDBKeyRange.bound()
:同时指定上下限IDBKeyRange.only()
:指定只包含一个值
// All keys ≤ x
var r1 = IDBKeyRange.upperBound(x);
// All keys < x
var r2 = IDBKeyRange.upperBound(x, true);
// All keys ≥ y
var r3 = IDBKeyRange.lowerBound(y);
// All keys > y
var r4 = IDBKeyRange.lowerBound(y, true);
// All keys ≥ x && ≤ y
var r5 = IDBKeyRange.bound(x, y);
// All keys > x &&< y
var r6 = IDBKeyRange.bound(x, y, true, true);
// All keys > x && ≤ y
var r7 = IDBKeyRange.bound(x, y, true, false);
// All keys ≥ x &&< y
var r8 = IDBKeyRange.bound(x, y, false, true);
// The key = z
var r9 = IDBKeyRange.only(z);
IDBKeyRange.lowerBound()
、IDBKeyRange.upperBound()
、IDBKeyRange.bound()
这三个方法默认包括端点值,可以传入一个布尔值,修改这个属性。
与之对应,IDBKeyRange 对象有四个只读属性。
IDBKeyRange.lower
:返回下限IDBKeyRange.lowerOpen
:布尔值,表示下限是否为开区间(即下限是否排除在范围之外)IDBKeyRange.upper
:返回上限IDBKeyRange.upperOpen
:布尔值,表示上限是否为开区间(即上限是否排除在范围之外)
IDBKeyRange 实例对象生成以后,将它作为参数输入 IDBObjectStore 或 IDBIndex 对象的 openCursor()
方法,就可以在所设定的范围内读取数据。
var t = db.transaction(['people'], 'readonly');
var store = t.objectStore('people');
var index = store.index('name');
var range = IDBKeyRange.bound('B', 'D');
index.openCursor(range).onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
console.log(cursor.key + ':');
for (var field in cursor.value) {
console.log(cursor.value[field]);
}
cursor.continue();
}
}
IDBKeyRange 有一个实例方法 includes(key)
,返回一个布尔值,表示某个主键是否包含在当前这个主键组之内。
var keyRangeValue = IDBKeyRange.bound('A', 'K', false, false);
keyRangeValue.includes('F') // true
keyRangeValue.includes('W') // false