• HTML5之IndexedDB使用详解


     随着firefox4正式版的推出,IndexedDB正式进入我们的视线。IndexedDB是HTML5-WebStorage的重要一环,是一种轻量级NOSQL数据库。相较之下,WebDataBase标准已经很长时间没有更新,大有被IndexedDB取代的意思。

    Section 1:起步,得到Database引用

    w3c为IndexedDB定义了很多接口,其中Database对象被定义为IDBDataBase。而得到IDBDataBase用的是工厂方法,即从IDBFactory中取得。浏览器对象中,实现了IDBFactory的只有indexedDB这个实例。

    大家可以先看下IDBFactory和IDBDataBase接口的定义

    Js代码  收藏代码
    1. interface IDBFactory {  
    2.     IDBRequest open (in DOMString name);  
    3.     IDBRequest deleteDatabase (in DOMString name);  
    4. };  
    5.   
    6. interface IDBDatabase : EventTarget {  
    7.     readonly attribute DOMString     name;  
    8.     readonly attribute DOMString     version;  
    9.     readonly attribute DOMStringList objectStoreNames;  
    10.     IDBObjectStore          createObjectStore (in DOMString name, in optional Object optionalParameters) raises (IDBDatabaseException);  
    11.     IDBRequest              deleteObjectStore (in DOMString name) raises (IDBDatabaseException);  
    12.     IDBVersionChangeRequest setVersion ([TreatNullAs=EmptyString] in DOMString version);  
    13.     IDBTransaction          transaction (in any storeNames, in optional unsigned short mode) raises (IDBDatabaseException);  
    14.     void                    close ();  
    15.              attribute Function      onabort;  
    16.              attribute Function      onerror;  
    17.              attribute Function      onversionchange;  
    18. };  
    19.   
    20. interface IDBRequest : EventTarget {  
    21.     readonly attribute any            result get raises (IDBDatabaseException);  
    22.     readonly attribute unsigned short errorCode get raises (IDBDatabaseException);  
    23.     readonly attribute Object         source;  
    24.     readonly attribute IDBTransaction transaction;  
    25.     const unsigned short LOADING = 1;  
    26.     const unsigned short DONE = 2;  
    27.     readonly attribute unsigned short readyState;  
    28.              attribute Function       onsuccess;  
    29.              attribute Function       onerror;  
    30. };  

    重要:IndexedDB中,几乎所有的操作都是采用了command->request->result的方式。比如查询一条记录,返回一个request,在request的result中得到查询结果。又比如打开数据库,返回一个request,在request的result中得到返回的数据库引用。

    从IDBFactory的方法体定义中可以看到,返回了一个IDBRequest对象。这个IDBRequest就是刚才所说的request。

    下面给出一个通用的得到IDBDataBase的方法

    Js代码  收藏代码
    1. if (!window.indexedDB) {  
    2.     window.indexedDB = window.mozIndexedDB || window.webkitIndexedDB;  
    3. }  
    4.   
    5. var request = indexedDB.open("MyTestDatabase");  
    6.   
    7. request.onsuccess = function(e) {  
    8.     // Obtain IDBDatabase   
    9.     // VERSION_CHANGE transaction callback  
    10.     var db = request.result;  
    11. }  

    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中被称为object store。

    下面给出object store接口的定义:

    Js代码  收藏代码
    1. interface IDBObjectStore {  
    2.     readonly attribute DOMString      name;  
    3.     readonly attribute DOMString      keyPath;  
    4.     readonly attribute DOMStringList  indexNames;  
    5.     readonly attribute IDBTransaction transaction;  
    6.     IDBRequest put (in any value, in optional any key) raises (IDBDatabaseException, DOMException);  
    7.     IDBRequest add (in any value, in optional any key) raises (IDBDatabaseException, DOMException);  
    8.     IDBRequest delete (in any key) raises (IDBDatabaseException);  
    9.     IDBRequest get (in any key) raises (IDBDatabaseException);  
    10.     IDBRequest clear () raises (IDBDatabaseException);  
    11.     IDBRequest openCursor (in optional any range, in optional unsigned short direction) raises (IDBDatabaseException);  
    12.     IDBIndex   createIndex (in DOMString name, in DOMString keyPath, in optional Object optionalParameters) raises (IDBDatabaseException);  
    13.     IDBIndex   index (in DOMString name) raises (IDBDatabaseException);  
    14.     void       deleteIndex (in DOMString indexName) raises (IDBDatabaseException);  
    15. };  

    大家可以看到IDBDatabase中有一个createObjectStore方法。但是取得IDBDatabase后直接调用会报Exception。原因在于createObjectStore不能在version_change 的transaction callback中被调用。

    下面给出通用的创建object store的代码

    Js代码  收藏代码
    1. var db = null;  
    2. var customerData = [  
    3.         {ssn: "444-44-4444", name: "Bill", age: 25, email: "bill@company.com", nickName: ["1", "2", "3"]},  
    4.         {ssn: "555-55-5555", name: "Donna", age: 34, email: "donna@home.org"},  
    5.         {ssn: "666-66-6666", name: "Jack", age: 14, email: "jack@sina.com.cn"}  
    6.     ];  
    7. request.onsuccess = function(e) {  
    8.     // Obtain IDBDatabase   
    9.     // VERSION_CHANGE transaction callback  
    10.     db = request.result;  
    11.       
    12.     if (db.version != "1.0") {  
    13.         var requestVersion = db.setVersion("1.0");  
    14.         requestVersion.onerror = function(event) {  
    15.             alert(event);  
    16.         }  
    17.         requestVersion.onsuccess = function(event) {  
    18.             createObjectStore(db);  
    19.         }  
    20.     }  
    21.       
    22.     db.close();  
    23. };  
    24.   
    25. function createObjectStore(db) {  
    26.   
    27.     if (db.objectStoreNames.contains('customers')) {  
    28.         db.deleteObjectStore("customers")  
    29.     }  
    30.     // Create Object Store  
    31.     // This method was not called from a VERSION_CHANGE transaction callback.  
    32.     var objectStore = db.createObjectStore("customers", {  
    33.         // primary key  
    34.         keyPath: "ssn",  
    35.         // auto increment  
    36.         autoIncrement: false  
    37.     });  
    38.       
    39.     objectStore.createIndex("name", "name", { unique: false });  
    40.       
    41.     objectStore.createIndex("email", "email", { unique: true });  
    42.       
    43.     // Add initial data  
    44.     for (var index = 0; index < customerData.length; index++) {  
    45.         objectStore.add(customerData[index]);  
    46.     }  
    47. }  

     以上代码创建了一个名为customers,PrimaryKey为ssn,并且不带自增序列的object store(表)。并为这个object store创建了两个索引(name和email).其中email是唯一键。并且为customers创建了初始数据。可以看到初始数据中可以嵌套多层结构。

    Section 3:事务和游标

    通过上面IDBDatabase接口的定义,我们可以从IDBDatabase中取得transaction。在indexedDB中,事务会自动提交或回滚。所以无需手动commit或者rollback。

    事务分为三种

    IDBTransaction.READ_ONLY              只读

    IDBTransaction.READ_WRITE            可读可写

    IDBTransaction.VERSION_CHANGE    版本升级

    我们用的最多的是前两种。如果不设置事务级别,则默认为READ_ONLY。

    游标是遍历object store的唯一方法。虽然firefox4中有getAll,但是相信在不久的将来,这个方法会被取缔。

    如果在打开游标的时候不设置,默认采用IDBCursor.NEXT

    下面给出得到事务对象的通用方法

    Js代码  收藏代码
    1. // 通过IDBDatabase得到IDBTransaction  
    2. var transaction = db.transaction(["customers"]);  
    3.   
    4. // 通过IDBTransaction得到IDBObjectStore  
    5. var objectStore = transaction.objectStore("customers");  
    6.   
    7. // 打开游标,遍历customers中所有数据  
    8. objectStore.openCursor().onsuccess = function(event) {  
    9.               
    10.     var cursor = event.target.result;  
    11.               
    12.     if (cursor) {  
    13.         var key = cursor.key;  
    14.         var rowData = cursor.value;  
    15.         alert(rowData.name);  
    16.         cursor.continue();  
    17.     }  
    18. }  

     上面代码中使用了游标,这里要注意,在调用了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代码  收藏代码
    1. // 只取得当前索引的值为Bill的数据  
    2. IDBKeyRange.only("Bill");  
    3.   
    4. // 只取得当前索引的值大于Bill,并且不包括Bill的数据  
    5. IDBKeyRange.lowerBound("Bill", true);  
    6.   
    7. // 只取得当前索引的值小于Bill,并且包括Bill的数据  
    8. IDBKeyRange.upperBound("Bill", false);  
    9.   
    10. // 取得当前索引的值介于Bill和Jack之间,并且包括Bill,但不包括Jack的数据  
    11. IDBKeyRange.bound("Bill", "Jack", false, true);  

     2)openCursor的第二个参数为游标方向。有4种

    IDBCursor.NEXT                                  顺序循环

    IDBCursor.NEXT_NO_DUPLICATE        顺序循环不重复

    IDBCursor.PREV                                  倒序循环

    IDBCursor.PREV_NO_DUPLICATE        倒序循环不重复

    例子:

    Java代码  收藏代码
    1. var boundKeyRange = IDBKeyRange.upperBound("Jack", false);  
    2. objectStore.index("name").openCursor(boundKeyRange, IDBCursor.PREV_NO_DUPLICATE).onsuccess = function(event) {  
    3.         var cursor = event.target.result;  
    4.           
    5.         if (!cursor) {  
    6.             return;  
    7.         }  
    8.           
    9.         var rowData = cursor.value;  
    10.           
    11.         alert(rowData.name);  
    12.         cursor.continue();  
    13.     };  

    完整实例请参考附件。注意,indexedDB必须要在发布环境(web容器)中才可以运行。

  • 相关阅读:
    Consuming RESTful Web服务
    任务调度
    查看公网出口ip
    Grafana变量
    正则表达式大杂烩
    seata 踩坑记录
    ES 重写分数查询
    浏览器下载文件乱码
    MySQL sql万花油优化
    ubuntu 使用杂记
  • 原文地址:https://www.cnblogs.com/xiaochao12345/p/3966874.html
Copyright © 2020-2023  润新知