HTML5之IndexedDB使用详解

来源:互联网 发布:淘宝连衣裙店铺推荐 编辑:程序博客网 时间:2024/05/01 11:31

HTML5之IndexedDB使用详解

HTML5NoSQL数据结构浏览器
 随着firefox4正式版的推出,IndexedDB正式进入我们的视线。IndexedDB是HTML5-WebStorage的重要一环,是一种轻量级NOSQL数据库。相较之下,WebDataBase标准已经很长时间没有更新,大有被IndexedDB取代的意思。
 
Section 1:起步,得到Database引用
w3c为IndexedDB定义了很多接口,其中Database对象被定义为IDBDataBase。而得到IDBDataBase用的是工厂方法,即从IDBFactory中取得。浏览器对象中,实现了IDBFactory的只有indexedDB这个实例。
大家可以先看下IDBFactory和IDBDataBase接口的定义
Js代码 
interface IDBFactory { 
    IDBRequestopen (in DOMString name); 
    IDBRequestdeleteDatabase (in DOMString name); 
}; 
 
interface IDBDatabase : EventTarget { 
    readonlyattributeDOMString    name; 
    readonlyattributeDOMString    version; 
    readonlyattribute DOMStringList objectStoreNames; 
   IDBObjectStore         createObjectStore (in DOMString name, in optional ObjectoptionalParameters) raises(IDBDatabaseException); 
   IDBRequest             deleteObjectStore (in DOMString name) raises(IDBDatabaseException); 
   IDBVersionChangeRequest setVersion ([TreatNullAs=EmptyString] inDOMString version); 
   IDBTransaction         transaction (in any storeNames, in optional unsigned short mode)raises (IDBDatabaseException); 
   void                   close (); 
            attributeFunction     onabort; 
            attributeFunction     onerror; 
            attributeFunction     onversionchange; 
}; 
 
interface IDBRequest : EventTarget { 
    readonlyattributeany           result get raises (IDBDatabaseException); 
    readonlyattribute unsigned short errorCode get raises(IDBDatabaseException); 
    readonlyattributeObject        source; 
    readonlyattribute IDBTransaction transaction; 
    constunsigned short LOADING = 1; 
    constunsigned short DONE = 2; 
    readonlyattribute unsigned short readyState; 
            attributeFunction      onsuccess; 
            attributeFunction      onerror; 
}; 
 
重要:IndexedDB中,几乎所有的操作都是采用了command->request->result的方式。比如查询一条记录,返回一个request,在request的result中得到查询结果。又比如打开数据库,返回一个request,在request的result中得到返回的数据库引用。
 
从IDBFactory的方法体定义中可以看到,返回了一个IDBRequest对象。这个IDBRequest就是刚才所说的request。
 
下面给出一个通用的得到IDBDataBase的方法
 
Js代码 
if (!windows.indexedDB) { 
   windows.indexedDB = window.mozIndexedDB ||window.webkitIndexedDB; 

 
var request =indexedDB.open("MyTestDatabase"); 
 
request.onsuccess = function(e) { 
    // ObtainIDBDatabase  
    //VERSION_CHANGE transaction callback 
    var db =request.result; 

 
Firefox4中使用IndexedDB的注意点:
1.indexedDB这个实例并不叫indexedDB,而是叫mozIndexedDB
2.indexedDB无法在iframe或者frame标签中使用
3.Firefox4中并未实现deleteDatabase方法(可能会在新版本中改进)
4.indexedDB.open并不能简单的看成是打开数据库,而是在打开数据库的基础上启动了一个version_change事件方法回调。在这个回调方法里自动启动了一个事务,用于version_change。IDBDatabase对象必须要在这个事务中才能取得。
 
 
Section 2:初始化object store
indexedDB标准建议,在初始化的时候创建表。以后每次打开浏览器,只需要check版本号。不需要第二次创建。而表在indexedDB中被称为objectstore。
下面给出object store接口的定义:
Js代码 
interface IDBObjectStore { 
    readonlyattributeDOMString     name; 
    readonlyattributeDOMString     keyPath; 
    readonlyattribute DOMStringList indexNames; 
    readonlyattribute IDBTransaction transaction; 
    IDBRequestput (in any value, in optional any key) raises(IDBDatabaseException, DOMException); 
    IDBRequestadd (in any value, in optional any key) raises(IDBDatabaseException, DOMException); 
    IDBRequestdelete (in any key) raises(IDBDatabaseException); 
    IDBRequestget (in any key) raises(IDBDatabaseException); 
    IDBRequestclear () raises (IDBDatabaseException); 
    IDBRequestopenCursor (in optional any range, in optional unsigned shortdirection) raises (IDBDatabaseException); 
   IDBIndex   createIndex (inDOMString name, in DOMString keyPath, in optional ObjectoptionalParameters) raises(IDBDatabaseException); 
   IDBIndex   index (in DOMStringname) raises (IDBDatabaseException); 
   void      deleteIndex (in DOMString indexName) raises(IDBDatabaseException); 
}; 
 
 
大家可以看到IDBDatabase中有一个createObjectStore方法。但是取得IDBDatabase后直接调用会报Exception。原因在于createObjectStore不能在version_change的transaction callback中被调用。
 
下面给出通用的创建object store的代码
Js代码 
var db = null; 
var customerData = [ 
       {ssn: "444-44-4444", name: "Bill", age: 25, email: "bill@company.com", nickName: ["1","2", "3"]}, 
       {ssn: "555-55-5555", name: "Donna", age: 34, email: "donna@home.org"}, 
       {ssn: "666-66-6666", name: "Jack", age: 14, email: "jack@sina.com.cn"} 
   ]; 
request.onsuccess = function(e) { 
    // ObtainIDBDatabase  
    //VERSION_CHANGE transaction callback 
    db =request.result; 
     
    if(db.version != "1.0") { 
       var requestVersion = db.setVersion("1.0"); 
       requestVersion.onerror = function(event) { 
           alert(event); 
       
       requestVersion.onsuccess = function(event){ 
           createObjectStore(db); 
       
   
     
   db.close(); 
}; 
 
function createObjectStore(db) { 
 
    if(db.objectStoreNames.contains('customers')){ 
       db.deleteObjectStore("customers") 
   
    // CreateObject Store 
    // Thismethod was not called from a VERSION_CHANGE transactioncallback. 
    varobjectStore = db.createObjectStore("customers",{ 
       // primary key 
       keyPath: "ssn", 
       // auto increment 
       autoIncrement: false 
   }); 
     
   objectStore.createIndex("name", "name", { unique: false}); 
     
   objectStore.createIndex("email", "email", { unique: true}); 
     
    // Addinitial data 
    for (varindex = 0; index < customerData.length; index++){ 
       objectStore.add(customerData[index]); 
   

 以上代码创建了一个名为customers,PrimaryKey为ssn,并且不带自增序列的objectstore(表)。并为这个objectstore创建了两个索引(name和email).其中email是唯一键。并且为customers创建了初始数据。可以看到初始数据中可以嵌套多层结构。
 
Section 3:事务和游标
通过上面IDBDatabase接口的定义,我们可以从IDBDatabase中取得transaction。在indexedDB中,事务会自动提交或回滚。所以无需手动commit或者rollback。
事务分为三种
IDBTransaction.READ_ONLY             只读
IDBTransaction.READ_WRITE           可读可写
IDBTransaction.VERSION_CHANGE   版本升级
我们用的最多的是前两种。如果不设置事务级别,则默认为READ_ONLY。
 
游标是遍历objectstore的唯一方法。虽然firefox4中有getAll,但是相信在不久的将来,这个方法会被取缔。
 
如果在打开游标的时候不设置,默认采用IDBCursor.NEXT
 
下面给出得到事务对象的通用方法
Js代码 
// 通过IDBDatabase得到IDBTransaction 
var transaction =db.transaction(["customers"]); 
 
// 通过IDBTransaction得到IDBObjectStore 
var objectStore =transaction.objectStore("customers"); 
 
// 打开游标,遍历customers中所有数据 
objectStore.openCursor().onsuccess = function(event){ 
             
    var cursor =event.target.result; 
             
    if (cursor){ 
       var key = cursor.key; 
       var rowData = cursor.value; 
       alert(rowData.name); 
       cursor.continue(); 
   

 上面代码中使用了游标,这里要注意,在调用了cursor.continue之后,cursor会重新调用onsuccess句柄上的方法。所以,以上代码的onsuccess实际上被调用了3遍。至于openCursor的使用方法,下个Section中会有提到
 
Section 4:索引查询
section3中的objectStore.openCursor是根据keyPath去查询的。如果想通过某个索引去查询,可以用objectStore.index(索引名).openCursor去查询
 
1)openCursor的第一个参数为查询条件,他需要传入一个IDBKeyRange对象。
IDBKeyRange的创建方式有4种,都是调用了IDBKeyRange的静态方法。分别代表了4种不同类型的条件。
Js代码 
// 只取得当前索引的值为Bill的数据 
IDBKeyRange.only("Bill"); 
 
// 只取得当前索引的值大于Bill,并且不包括Bill的数据 
IDBKeyRange.lowerBound("Bill", true); 
 
// 只取得当前索引的值小于Bill,并且包括Bill的数据 
IDBKeyRange.upperBound("Bill", false); 
 
//取得当前索引的值介于Bill和Jack之间,并且包括Bill,但不包括Jack的数据 
IDBKeyRange.bound("Bill", "Jack", false,true); 
 2)openCursor的第二个参数为游标方向。有4种
IDBCursor.NEXT                                 顺序循环
IDBCursor.NEXT_NO_DUPLICATE       顺序循环不重复
IDBCursor.PREV                                 倒序循环
IDBCursor.PREV_NO_DUPLICATE       倒序循环不重复
 
例子:
Java代码 
var boundKeyRange = IDBKeyRange.upperBound("Jack",false); 
objectStore.index("name").openCursor(boundKeyRange,IDBCursor.PREV_NO_DUPLICATE).onsuccess = function(event){ 
       var cursor = event.target.result; 
         
       if (!cursor) { 
           return; 
       
         
       var rowData = cursor.value; 
         
       alert(rowData.name); 
       cursor.continue(); 
   }; 
 
完整实例请参考附件。注意,indexedDB必须要在发布环境(web容器)中才可以运行。

0 0