介绍
IndexedDB就是一个数据库
其最大的特点是: 使用对象保存数据,而不是使用表来保存数据,同时,它是异步的
使用方式
连接数据库
要使用它必须先打开,通过 indexDB.open(name, version)
方法打开一个数据库
- name : 表示数据要打开的数据库的名称
- version:为打开数据库的版本号
indexDB.open()
方法的原理
分为两种情况:
1. 传入的数据库不存在
当传入的数据库不存在时,该方法就会创建一个名为name的数据库,并打开它,此时,会先触发upgradeneeded事件
;调用该函数会返回一个IDBRequest
对象,可以在该对象上添加onsuccess事件
和onerror事件
。
注意:当打开一个不存在的数据库时会触发upgradeneeded事件
,这是触发该事件的一种途径,为什么会触发该事件呢?该事件有什么作用?留个疑问在这儿,等会解答。
2. 传入的数据库存在
这里分为两种情况:
当传入的数据库存在,且version版本号与将要打开的数据库版本号也相同
则直接打开该数据库,如果成功,则会触发onsuccess事件
,失败则触发onerror事件
注意:这里并不会触发upgradeneeded事件
,为什么?留个疑问当传入的数据库存在,但是传入的version版本号高于将要打开的数据库的版本号
则直接打开该数据库,同时触发upgradeneeded事件
,然后再触发onsuccess事件
和onerror事件
,这里也触发了onupdateneeded事件
upgradeneeded
事件
触发该事件的条件:当打开的数据库不存在,或者传入的数据库版本version高于当前版本,则会触发该事件
upgradeneeded
事件的作用:当打开了一个数据库之后,需要开辟一个名为:对象存储空间 的玩意(可以理解为数据就是存放在这个空间里面,一个数据库可以创建多个对象存储空间),而 对象存储空间 只能在upgradeneeded
事件的处理函数中创建
使用时,注意以下两种情况:
当我们第一次打开创建数据库时,会触发
upgradeneeded
事件,我们就需要在其中创建对象存储空间当我们对数据库版本进行更新时,也会触发该事件,这时可以在此创建新的对象存储空间,原来的对象存储空间仍然存在
注意:如果需要对对象存储空间进行修改,那么只能先将存储在它里面的数据读取出来,再将其删除,然后使用新的选项去创建它,再写入原来的数据
打开数据库并创建对象存储空间的代码:
// 对于该API,各浏览器还未同一,所以需要对一些接口添加前缀
window.indexedDB = window.indexedDB || window.msIndexedDB || window.mozIndexedDB || window.webkitIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"};
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBTransaction;
// 判断浏览器是否支持IndexedDB
if (!window.indexedDB) {
window.alert("Your browser doesn't support a stable version of IndexedDB.")
}
var request , db;
// 打开或创建 名为dbName的数据库
request = window.indexedDB.open('dbName', 2)
request.onsuccess = function (event) {
db = event.target.result;
}
request.onerror = function (event) {
console.log('错误代码: ' + event.target.errorCode);
}
request.onupgradeneeded = function(event) {
db = event.target.result; //
// 创建一个 对象存储空间,名为customers
var objectStore = db.createObjectStore('customers', {keyPath: 'ssn'});
// 对于某些数据,可以为一个对象存储空间指定多个键。比如,若要通过用户ID 和用户名 两种方式来保存用户资料,就需要通过两个键来存取记录
// 因此可以使用createIndex,名字是有可能重复的,所以其unique 设置为 false ;第一个name是索引的名字,该名字是索引的名字,第二个name是索引的属性的名字,该名字要与对象中的属性相同
objectStore.createIndex('name', 'name', { unique: false});
// 创建一个email的索引,该email是独特的,所以 unique 设置为 true
objectStore.createIndex('email', 'email', { unique: true});
}
存储数据
存储数据有两种方法:add()方法 和 put()方法
这两种方法的区别主要体现在:当要添加数据的对象存储空间中已经存在有相同键的数据时,使用add()方法添加数据会报错误,而put()方法则会对现有数据进行更新,所以add()方法一般用于初始化数据,而put()方法用于更新数据
代码如下:
// customerData 为要存储的数据
const customerData = [{ ssn: '444-44-4444', name: 'AAA', age: 35, email: '[[email protected]](mailto:[email protected])'},{ ssn: '666-66-6666', name: 'CCC', age: 35, email: '[[email protected]](mailto:[email protected])'},{ ssn: '777-77-7777', name: 'DDD', age: 32, email: '[[email protected]](mailto:[email protected])'},{ ssn: '555-55-5555', name: 'BBB', age: 32, email: '[[email protected]](mailto:[email protected])'},
];
// 创建一个事务,该事务将要对名为“customers”的对象存储空间进行 read和write 操作,并返回事务索引
let transaction = db.transaction('customers', 'readwrite');
// 取得索引后,使用objectStore()方法并传入存储空间的名称,就可以访问特定的存储空间,这两步是必须的
let store = transaction.objectStore('customers');
// 添加数据到数据库中
for (var i in customerData) {
// 返回的req也是一个对象,可以为其添加onsuccess和onerror事件,来检测数据是否添加成功
let req = store.put(customerData[i]); // 往一个存储空间中添加数据
}
// 判断事务整个操作完成
transaction.oncomplete = function(event) {
console.log(event.target);
alert('存储数据完成');
};
}
如上就将数据存储到数据库dbNames的customers对象存储空间中
上面代码中提到了 [事务],这里先记住:凡是涉及到对数据库的读写删除操作,都需要通过 [事务] 来完成
事务和查询操作数据
最简单的创建事务的方式是:
var transaction = db.transaction(); // db就是前面的数据库对象
这种方式创建的事务,只能读取数据库中保存的所有对象
一般用法是:
var transaction = db.transaction('customes', 'readwrite');
表示只加载customers对象存储空间中的数据,并且是以可读可写的方式加载
如果不传第二个参数,则表示只可访问,不可修改;
这里返回的transaction是事务的索引
然后使用objectStore()
方法并传入对象存储空间的名称,就可以访问特定的存储空间了;
如下:
let transaction = db.transaction('customers', 'readwrite');
let store = transaction.objectStore('customers');
取得了上面的store后,我们可以使用如下方法对数据进行操作:
- add()和put()方法:用于存储数据
let req = store.add(data);
- get(key)方法:获取键为key的对象
let req = store.get(key);
- delete(key)方法:删除键为key的对象
let req = store.delete(key);
- clear()方法:清空对象存储空间中的所有对象
let req = store.clear();
使用上述方法会返回一个对象,通过对其添加onsuccess和onerror事件,可以检测操作是否成功
注意:通过oncomplete事件对象,访问不到get()请求返回的任何数据,必须在响应请求的onsuccess事件处理程序中才能访问到数据
使用游标查询数据
使用事务可以直接通过 已知的键检索单个对象。而在需要检索多个对象时,则需要在事务内创建游标。
游标并不会提前收集结果,游标先指向结果中的第一项,在接到查找下一项的指令时,才会指向下一项
如下:
let transaction = db.transaction('customers', 'readwrite'),
let store = transaction.objectStore('customers'),
let request = store.openCursor(null) ; // 这里创建游标
request.onsuccess = function (event) {
// event.target.result 中保存的是在存储空间中查询到的对象
// event.target.result 中有几个属性值,可以了解到查询到的对象中的细节,
// key: 当前访问的对象的键
// value:当前访问的实际对象
// primaryKey: 游标使用的键
// direction:数值,表示游标移动的方向
let cursor = event.target.result;
let value, updateRequest, deleteRequest;
// 这里必须要检查游标中是否有数据
if (cursor) {
if (cursor.key === '555-55-5555') {
value = cursor.value; // 获取到实际的访问对象
value.name = 'hexon'; // 修改对象的name属性
// 调用update()方法可以用指定的对象,更新对象的value
updateRequest = cursor.update(value);
updateRequest.onsuccess = function() {
// 处理成功
}
}
cursor.continue() ; // 移动到下一项,会触发下一次请求,同时成功则触发request.onsuccess
}
}
上面例子中,可以使用cursor.delete()
方法删除当前项
键范围
游标也可以接受一个键,也就是通过键来设定游标查找的范围;
代码如下: