IndexedDB
基本概念
IndexedDB 是一个比较复杂的 API,涉及不少概念。它把不同的实体,抽象成一个个对象接口。学习这个 API,就是学习它的各种对象接口。
- 数据库:IDBDatabase 对象
- 对象仓库:IDBObjectStore 对象
- 索引: IDBIndex 对象
- 事务: IDBTransaction 对象
- 操作请求:IDBRequest 对象
- 指针: IDBCursor 对象
- 主键集合:IDBKeyRange 对象
open database
var request = window.indexedDB.open(databaseName, version) // databaseName: 数据库名 version: 版本
// 如果指定的数据库不存在,将会创建,版本默认为1
// return IDBRequest 对象。这个对象有三种事件error、success、upgradeneeded,用于打开数据库后的操作。
request.onerror = function (event) {
console.log('error')
}
request.onsuccess = function (event) {
let db = request.result
console.log('success')
}
request.onupgradeneeded = function (event) {
let db = event.target.result
console.log('update 当指定版本大于版本,就会触发升级事件 第一次打开数据库时,会先触发upgradeneeded事件,然后触发success事件。')
}
//成功后,即可通过request.result 访问IDBdatabse对象IDBDatabase 对象有以下属性。
IDBDatabase.name:字符串,数据库名称。IDBDatabase.version:整数,数据库版本。数据库第一次创建时,该属性为空字符串。IDBDatabase.objectStoreNames:DOMStringList 对象(字符串的集合),包含当前数据的所有 object store 的名字。IDBDatabase.onabort:指定 abort 事件(事务中止)的监听函数。IDBDatabase.onclose:指定 close 事件(数据库意外关闭)的监听函数。IDBDatabase.onerror:指定 error 事件(访问数据库失败)的监听函数。IDBDatabase.onversionchange:数据库版本变化时触发(发生upgradeneeded事件,或调用indexedDB.deleteDatabase())。
IDBTransaction 对象
IDBTransaction 对象用来异步操作数据库事务,所有的读写操作都要通过这个对象进行,IDBDatabase.transaction()方法返回的就是一个 IDBTransaction 对象。
IDBTransaction.db:返回当前事务所在的数据库对象 IDBDatabase。IDBTransaction.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 对象
IDBObjectStore.index()方法可以获取 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.openKeyCursor():该方法与IDBIndex.openCursor()方法相似,区别是遍历所有条目的主键。
IDBCursor 对象
IDBCursor 对象代表指针对象,用来遍历数据仓库(IDBObjectStore)或索引(IDBIndex)的记录。
IDBCursor 对象一般通过IDBObjectStore.openCursor()方法获得。
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') // falsecreateDatabase
request.onupgradeneeded = function (event) {
let db = event.target.result
if (!db.objectStoreNames.contains('persion')) let objcetStore = db.createObjectStore('persion', {keyPath: 'id'})
// db.createObjectStore(databaseName, options) options: keyPath 主键 或 autoIncrement 设置为true,两者只能存在一个
}createIndex
objcetStore.createIndex()//方法用于新建当前数据库的一个索引。该方法只能在VersionChange监听函数里面调用,只有存在数据库后才能使用。
objectStore.createIndex(indexName, keyPath, objectParameters)
该方法可以接受三个参数。
indexName:索引名
keyPath:主键
objectParameters:配置对象(可选)
第三个参数可以配置以下属性。
unique:如果设为true,将不允许重复的值
multiEntry:如果设为true,对于有多个值的主键数组,每个值将在索引里面新建一个条目,否则主键数组对应一个条目。add
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();上面代码中,写入数据需要新建一个事务。新建时必须指定表格名称和操作模式(“只读”或“读写”)。新建事务以后,通过IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 对象,再通过表格对象的add()方法,向表格写入一条记录。
写入操作是一个异步操作,通过监听连接对象的success事件和error事件,了解是否写入成功。
read
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();上面代码中,objectStore.get()方法用于读取数据,参数是主键的值
map
遍历数据表格的所有记录,要使用指针对象 IDBCursor。
function readAll() {
var objectStore = db.transaction('person').objectStore('person');
objectStore.openCursor().onsuccess = function (event) {
var cursor = 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();上面代码中,新建指针对象的openCursor()方法是一个异步操作,所以要监听success事件。
update
更新数据要使用IDBObject.put()方法。
function 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();上面代码中,put()方法自动更新了主键为1的记录。
delete
IDBObjectStore.delete()方法用于删除记录。
function remove() {
var request = db.transaction(['person'], 'readwrite')
.objectStore('person')
.delete(1);
request.onsuccess = function (event) {
console.log('数据删除成功');
};
}
remove();use Index
索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键(即从主键取值)。
假定新建表格的时候,对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 {
// ...
}
}