Web數據持久化存儲IndexedDB(不常用)


IndexedDB是在瀏覽器中保存結構化數據的一種數據庫,為了替換WebSQL(標准已廢棄,但被廣泛支持)而出現。IndexedDB使用NoSQL的形式來操作數據庫,保存和讀取是JavaScript對象,同時還支持查詢及搜索。

下面由5個方面講述:

1. 數據庫初始化

2. 對象存儲空間(ObjectStore)

3. 事務

4. 游標查詢

5. 索引

數據庫初始化

IndexedDB保存的是對象,而不是使用表保存數據。打開數據庫使用indexDB.open方法,這方法有兩個參數,第一個是數據庫名稱,第二個是數據版本號。

PS:IndexedDB的操作完全是異步進行的,每一次IndexedDB操作,都需要注冊onerror或onsuccess事件處理程序。

     var DB_NAME = 'DEMO';
     var DB_VERSION = 2; //使用正整數,別用浮點型
     var db;
 
     function initDb() {
          console.debug("initDb ...");
          var req = indexedDB.open(DB_NAME, DB_VERSION);
          req.onsuccess = function (evt) {
               db = evt.target.result;
               console.debug("initDb opened");
          };
          req.onerror = function (evt) {
               console.error("initDb error:", evt.target.errorCode || evt.target.error);
          };
 
          //增加數據庫版本號時,會觸發onupgradeneeded事件(會在onsuccess之前被調用)
          req.onupgradeneeded = function (evt) {
               console.debug("initDb.onupgradeneeded");
          };
     }

PS:這里要注意的是,數據庫版本只會有最新一個,不會同時存在兩個版本的同名數據庫。

對象存儲空間(ObjectStore)

對象存儲空間(ObjectStore)可以想象成關系數據庫的表,在初始化DB觸發onupgradeneeded時,創建ObjectStore。使用createObjectStore方法,第一個參數是對象名,第二個參數是對象屬性,一般是設置keyPath(作為鍵使用)。

     req.onupgradeneeded = function (evt) {
          console.debug("initDb.onupgradeneeded");
          var db = evt.currentTarget.result;
          //ObjectStore必須在onupgradeneeded里創建,其他地方將會創建失敗
          var usersStore = db.createObjectStore("users", { keyPath : "id" });
     };

效果如下:

事務

所有讀取或修改數據的操作,都要通過事務來完成。創建事務使用transaction方法,第一個參數是需要訪問的ObjectStore,第二個參數是訪問模式(readwrite、readonly,默認是只讀)。

添加數據

function addData(){
     var users = [{
          id : '001',
          name : '劉亦菲',
          age : 18
     },{
          id : '002',
          name : '楊冪',
          age : 19
     }];
 
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var i = 0, len = users.length;
     while(i < len){
          store.add(users[i++]);
     }
}

獲取數據

function getData(){
     var tx = db.transaction("users");
     var store = tx.objectStore("users");
     var req = store.get("001");
     req.onsuccess = function (evt) {
          var res = evt.target.result;
          console.debug(res);
     };
     req.onerror = function (evt) {
          console.error("getData error:", evt.target.errorCode || evt.target.error);
     };
}

修改數據

function updateData(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var req = store.put({
          id : '001',
          name : '劉亦菲-小龍女',
          age : 18
     });
     req.onsuccess = function (evt) {
          console.debug("updateData success");
     };
     req.onerror = function (evt) {
          console.error("updateData error:", evt.target.errorCode || evt.target.error);
     };
}

刪除數據

function delData(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var req = store.delete("001");
     req.onsuccess = function (evt) {
          console.debug("delData success");
     };
     req.onerror = function (evt) {
          console.error("delData error:", evt.target.errorCode || evt.target.error);
     };
} 

清空數據

function clearData(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var req = store.clear();
     req.onsuccess = function (evt) {
          console.debug("clearData success");
     };
     req.onerror = function (evt) {
          console.error("clearData error:", evt.target.errorCode || evt.target.error);
     };
}

游標查詢

使用事務可以直接通過鍵檢索單個對象,而需要檢索多個對象時候就需要使用游標。游標是指向結果集的指針,不提前收集結果。游標指針會先指向結果中的第一項,在接到查找下一項指令時,才會指向下一項。

function openCursor(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var req = store.openCursor();
     req.onsuccess = function (evt) {
          var cursor = evt.target.result;
          if(cursor){ //必要檢查
               var value = cursor.value;
               console.log(value);
               if(value.name == '楊冪'){
                    value.age = 16;
                    cursor.update(value); //修改數據(必須是讀寫模式)
               }
               if(value.name == '柳岩'){
                    cursor.delete();  //刪除當前項
               }
               cursor.continue(); //移動到下一項
          }
     };
     req.onerror = function (evt) {
          console.error("openCursor error:", evt.target.errorCode || evt.target.error);
     };
}

這里有幾點要注意:

1. 如果需要修改或刪除數據,就需要打開成讀寫模式。

2. cursor的非空校驗是必要的。

3. 修改或刪除的操作也是有onsuccess和onerror的,只是在示例中沒有寫出來。

4. 調用continue才會移動到下一項

另外可以設置游標的鍵范圍和游標的方向,即打開openCursor方法時可以傳這兩個參數(openCursor(鍵范圍,方向)),第一個參數是object類型,第二個參數是字符串類型。

游標鍵范圍

鍵范圍由IDBKeyRange的實例表示。

IDBKeyRange.only('001');  //只想要鍵為001的結果
IDBKeyRange.lowerBound('002'); //從鍵為002開始,到最后
IDBKeyRange.lowerBound('002', true); //從鍵為002開始,但忽略002,到最后
IDBKeyRange.upperBound('002'); //從頭開始,到鍵為002為止
IDBKeyRange.upperBound('002', true); //從頭開始,到鍵為002為止,但忽略002
IDBKeyRange.bound('001', '005'); //從001開始,到為005為止
IDBKeyRange.bound('001', '005', true, true); //從001開始,到為005為止,但忽略001、005

游標方向

next : 從第一項到最后一項(默認)

prev : 從最后一項到第一項

索引

當需要使用其他屬性(非主鍵)獲取數據時,就要預先創建索引,然后使用索引獲取數據。

創建索引(在數據庫初始化onupgradeneeded事件時)

第一個參數是索引名字,第二個參數是索引的屬性的名字,第三個是一個options對象。一般是指定unique,設置索引是否唯一。

usersStore.createIndex("name", "name", { unique : false });

索引獲取數據

function indexGetData(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var index = store.index("name");
     var req = index.get("楊冪")
     req.onsuccess = function (evt) {
          console.debug("indexGet success" , evt.target.result);
     };
     req.onerror = function (evt) {
          console.error("indexGet error:", evt.target.errorCode || evt.target.error);
     };
}

function indexOpenCursor(){
     var tx = db.transaction("users", READ_WRITE);
     var store = tx.objectStore("users");
     var index = store.index("name");
     var req = index.openCursor();
     req.onsuccess = function (evt) {
          var cursor = evt.target.result;
          if(cursor){ //必要檢查
               var value = cursor.value;
               console.log(value);
               cursor.continue(); //移動到下一項
          }
     };
     req.onerror = function (evt) {
          console.error("openCursor error:", evt.target.errorCode || evt.target.error);
     };
}

PS:索引用法跟普通取值和游標取值一樣

對象存儲所有索引

function indexNames(){
     var tx = db.transaction("users", READ_WRITE);
    var store = tx.objectStore("users");
     var indexNames = store.indexNames;
     var index, i = 0, len = indexNames.length;
     while(i < len){
          index = store.index(indexNames[i++]);
          console.log(index);
     }
}

瀏覽器支持情況

PS:圖表來源->http://caniuse.com/#feat=indexeddb

總結

在使用IndexedDB時候,有人可能會拿WebSQL來比較,然后發現IndexedDB不能做表連接(因為根本沒有這東西),也就是要查出一個數據,可能得分幾次進行。

例如學生、課程、分數三個表數據,想查出某個學生的課程成績,就得三個表連接,WebSQL分分鍾信手拈來。但是如果你用IndexedDB,就得分三次查找,先拿出那個學生,再拿出課程,然后再拿成績。

這樣看起來IndexedDB很蠢,這樣就進入誤區了,你為什么要這么去存你要展示的數據,NoSql就用NoSql東西,就直接以一個對象存學生成績,一次查找就行了。

示例下載:http://files.cnblogs.com/files/lovesong/IndexedDBdemo.zip

 

本文為原創文章,轉載請保留原出處,方便溯源,如有錯誤地方,謝謝指正。

本文地址 :http://www.cnblogs.com/lovesong/p/5055384.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM