随着浏览器的处理能力不断增强,产生了将大量数据储存在客户端能力的需求,这样可以减少用户等待从服务器获取数据的时间。现有的浏览器端数据储存方案,都不适合储存大量数据:Cookie 不超过4KB,且每次请求都会发送回服务器端;LocalStorage 在 2.5MB 到 10MB 之间(各浏览器不同)。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。
indexed DB(Indexed Database API)是浏览器中保存结构化数据的一种数据库,其特点是:键值对储存、异步、支持事务、同域限制、储存空间大、支持二进制储存。( IndexedDB 支持事务意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回到事务发生之前的状态,不存在只改写一部分数据的情况。)
1.首先需要根据不同浏览器的内核,创建indexedDB对象,如下:
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
打开一个数据库,打开数据库的结果时,有可能触发4种事件:
*success:打开成功。
*error:打开失败。
*upgradeneeded:第一次打开该数据库,或者数据库版本发生变化。
*blocked:上一次的数据库连接还未关闭。
第一次打开数据库时,会先触发upgradeneeded事件,然后触发success事件。
var request = indexedDB.open("数据库名称");
request.onsuccess = function(event)
{
……var db = event.target.result
}
request.onerror = function (event)
{
……event.target.errorCode
}
openRequest.onupgradeneeded = function(event)
{
……
}
2.获得数据库实例以后,就可以用实例对象的方法操作数据库。
2.1 createObjectStore方法用于创建存放数据的“对象存储空间”(object store),类似于传统关系型数据库的表格。
var store = db.createObjectStore("users",{keyPath: "username"});
创建了一个名为users的对象存储空间,如果该对象存储空间已经存在,就会抛出一个错误。为了避免出错,需要用到objectStoreNames属性,检查已有哪些对象仓库。
if(!db.objectStoreNames.contains("users")) {
db.createObjectStore("users");
}
第二个参数中的keyPath属性就是空间中要保存的对象的一个属性,这个属性将作为存储空间的键来使用。
var store = db.createObjectStore("users", { autoIncrement: true });
autoIncrement属性表示,是否使用自动递增的整数作为键名(第一个数据为1,第二个数据为2,以此类推),默认为false。一般来说,keyPath和autoIncrement属性只要使用一个就够了。
2.2 transaction方法用于创建一个数据库事务。向数据库添加数据之前,必须先创建数据库事务。
var transaction = db.transaction("users",IDBTransaction.READ_WRITE);
第一个参数可以使存储空间名称,也可以是多个存储空间名称字符串数组;第二个参数为访问模式(IDBTransaction.READ_WRITE、READ_ONLY、CHANGE);
transaction方法返回一个事务对象,该对象的objectStore方法用于获取指定的对象仓库:
var store = transaction.objectStore("users");
transaction方法有三个事件:abort:事务中断;complete:事务完成;error:事务出错。 可以用来定义回调函数。
transaction.objectStore("users")对象的方法,用于操作数据:
(1)添加数据:add方法,第一个参数是所要添加的数据,第二个参数是这条数据对应的键名(key)。
(2)读取数据:get方法,参数是数据的键名;
(3)更新记录:put方法,put方法的用法与add方法相近。
(4)删除记录:delete方法,参数是数据的键名。
(5)删除所有对象:clear方法
(6)遍历数据:openCursor方法
这些方法都是异步操作,均返回请求对象,具有error和success事件;
request = store.openCursor(键范围,游标方向);
request.onsuccess = function(event){
var cursor = event.target.result;
}
cursor: 属性--value、key、direction、primaryKey;方法--update()、delete()、continue(key)、advance(count)。
键范围有四种定义方式:
var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange ;
1: var onlyRange = IDBKeyRange.only(键) ;
2.var lowerRange = IDBKeyRange.lowerBound(键,[true]);
3. var upperRange = IDBKeyRange.upperBound(键,[true]);
4. var boundRange = IDBKeyRange.bound(键, 键, [true/false], [true/false])
参数true表示忽略此键的对象,从它的下一个对象开始;
游标方向的设定:
var IDBCursor= window.IDBCursor || window.webkitIDBCursor;
request = store.openCursor(键范围, IDBCursor.NEXT/IDBCursor.PREV/IDBCursor.PREV_NO_DUPLICATE/IDBCursor.NEXT_NO_DUPLICATE);
2.3 createIndex方法用于创建索引;可以指定数据对象的某个属性来建立索引。
store.createIndex("name","name", {unique:false});
store.createIndex("email","email", {unique:true});
createIndex方法接受三个参数,第一个是索引名称,第二个是建立索引的属性名,第三个是参数对象,用来设置索引特性。unique表示索引所在的属性是否有唯一值。
有了索引以后,就可以针对索引所在的属性读取数据。index方法用于从对象仓库返回指定的索引。
var index = store.index("name"),
request = index.openCursor();
event.result.key中保存着索引键,event.result.value中保存对应对象
var index = store.index("name"),
request = index.openKeyCursor();
event.result.key中保存着索引键,event.result.value中保存着主键
var index = store.index("name");
var request = index.get(name);
event.result.value中保存对应对象
var index = store.index("name");
var request = index.getKey(name);
event.result.value中保存着主键的值
IDBIndex对象的属性:name、keyPath、cbjectStore、unique;
对象存储空间的indexNames属性可以访问到该空间建立的所有索引;对象存储空间的deleteIndex(name)方法可以删除索引;
2.4 并发问题
如果浏览器的两个不同标签打开同一个页面,那么一个页面试图更新而另一个页面尚未准备就绪的数据库的问题就可能发生,因此每次成功打开数据库时,需要制定onversionchange事件处理程序,当同一个来源的另一个标签页调用setVersion()时就会执行这个回调函数,这个事件的最佳方式是立即关闭数据库db.close();
调用setVersion()时,还需指定请求的onblocked事件处理程序,当你想要更新数据库版本但是另一个标签页已经打开数据库的情况下,就会触发这个事件,此时,最好先通知用户关闭其他标签页,然后再重新调用setVersion()。