IndexedDB(一:基本使用)

BothEyes1993發表於2018-12-09

在HTML5本地儲存——Web SQL Database提到過Web SQL Database實際上已經被廢棄,而HTML5的支援的本地儲存實際上變成了 Web Storage(Local Storage和Session Storage)與IndexedDB。Web Storage使用簡單字串鍵值對在本地儲存資料,方便靈活,但是對於大量結構化資料儲存力不從心,IndexedDB是為了能夠在客戶端儲存大量的結構化資料,並且使用索引高效檢索的API。

非同步API

在IndexedDB大部分操作並不是我們常用的呼叫方法,返回結果的模式,而是請求——響應的模式,比如開啟資料庫的操作

var request=window.indexedDB.open('testDB');
複製程式碼

這條指令並不會返回一個DB物件的控制程式碼,我們得到的是一個IDBOpenDBRequest物件,而我們希望得到的DB物件在其result屬性中,

在這裡插入圖片描述
這條指令請求的響應是一個 IDBDatabase物件,這就是IndexedDB物件,
在這裡插入圖片描述

除了result,IDBOpenDBRequest介面定義了幾個重要屬性 ● onerror: 請求失敗的回撥函式控制程式碼 ● onsuccess:請求成功的回撥函式控制程式碼 ● onupgradeneeded:請求資料庫版本變化控制程式碼

所謂非同步API是指並不是這條指令執行完畢,我們就可以使用request.result來獲取indexedDB物件了,就像使用ajax一樣,語句執行完並不代表已經獲取到了物件,所以我們一般在其回撥函式中處理。

建立資料庫

剛才的語句已經展示瞭如何開啟一個indexedDB資料庫,呼叫indexedDB.open方法就可以建立或者開啟一個indexedDB。看一個完整的處理

function openDB (name) {
            var request=window.indexedDB.open(name);
            request.onerror=function(e){
                console.log('OPen Error!');
            };
            request.onsuccess=function(e){
                myDB.db=e.target.result;
            };
        }

        var myDB={
            name:'test',
            version:1,
            db:null
        };
        openDB(myDB.name);
複製程式碼

程式碼中定義了一個myDB物件,在建立indexedDB request的成功毀掉函式中,把request獲取的DB物件賦值給了myDB的db屬性,這樣就可以使用myDB.db來訪問建立的indexedDB了。

version

我們注意到除了onerror和onsuccess,IDBOpenDBRequest還有一個類似回撥函式控制程式碼——onupgradeneeded。這個控制程式碼在我們請求開啟的資料庫的版本號和已經存在的資料庫版本號不一致的時候呼叫。 indexedDB.open()方法還有第二個可選引數,資料庫版本號,資料庫建立的時候預設版本號為1,當我們傳入的版本號和資料庫當前版本號不一致的時候onupgradeneeded就會被呼叫,當然我們不能試圖開啟比當前資料庫版本低的version,否則呼叫的就是onerror了,修改一下剛才例子

function openDB (name,version) {
            var version=version || 1;
            var request=window.indexedDB.open(name,version);
            request.onerror=function(e){
                console.log(e.currentTarget.error.message);
            };
            request.onsuccess=function(e){
                myDB.db=e.target.result;
            };
            request.onupgradeneeded=function(e){
                console.log('DB version changed to '+version);
            };
        }

        var myDB={
            name:'test',
            version:3,
            db:null
        };
        openDB(myDB.name,myDB.version);
複製程式碼

由於剛才已經建立了版本為1的資料庫,開啟版本為3的時候,會在控制檯輸出:DB version changed to 3

關閉與刪除資料庫

關閉資料庫可以直接呼叫資料庫物件的close方法

function closeDB(db){
            db.close();
        }
複製程式碼

刪除資料庫使用indexedDB物件的deleteDatabase方法

function deleteDB(name){
            indexedDB.deleteDatabase(name);
        }
複製程式碼

簡單呼叫

var myDB={
            name:'test',
            version:3,
            db:null
        };
        openDB(myDB.name,myDB.version);
        setTimeout(function(){
            closeDB(myDB.db);
            deleteDB(myDB.name);
        },500);
複製程式碼

由於非同步API願意,不能保證能夠在closeDB方法呼叫前獲取db物件(實際上獲取db物件也比執行一條語句慢得多),所以用了setTimeout延遲了一下。當然我們注意到每個indexedDB例項都有onclose回撥函式控制程式碼,用以資料庫關閉的時候處理,有興趣同學可以試試,原理很簡單,不演示了。

object store

有了資料庫後我們自然希望建立一個表用來儲存資料,但indexedDB中沒有表的概念,而是objectStore,一個資料庫中可以包含多個objectStore,objectStore是一個靈活的資料結構,可以存放多種型別資料。也就是說一個objectStore相當於一張表,裡面儲存的每條資料和一個鍵相關聯。

我們可以使用每條記錄中的某個指定欄位作為鍵值(keyPath),也可以使用自動生成的遞增數字作為鍵值(keyGenerator),也可以不指定。選擇鍵的型別不同,objectStore可以儲存的資料結構也有差異

在這裡插入圖片描述

事務

在對新資料庫做任何事情之前,需要開始一個事務。事務中需要指定該事務跨越哪些object store。 事務具有三種模式

  1. 只讀:read,不能修改資料庫資料,可以併發執行
  2. 讀寫:readwrite,可以進行讀寫操作
  3. 版本變更:verionchange
var transaction=db.transaction([students','taecher']);  //開啟一個事務,使用students 和teacher object store
var objectStore=transaction.objectStore('students'); //獲取students object store
複製程式碼

給object store新增資料

呼叫資料庫例項的createObjectStore方法可以建立object store,方法有兩個引數:store name和鍵型別。呼叫store的add方法新增資料。有了上面知識,我們可以向object store內新增資料了

keyPath

因為對新資料的操作都需要在transaction中進行,而transaction又要求指定object store,所以我們只能在建立資料庫的時候初始化object store以供後面使用,這正是onupgradeneeded的一個重要作用,修改一下之前程式碼

function openDB (name,version) {
            var version=version || 1;
            var request=window.indexedDB.open(name,version);
            request.onerror=function(e){
                console.log(e.currentTarget.error.message);
            };
            request.onsuccess=function(e){
                myDB.db=e.target.result;
            };
            request.onupgradeneeded=function(e){
                var db=e.target.result;
                if(!db.objectStoreNames.contains('students')){
                    db.createObjectStore('students',{keyPath:"id"});
                }
                console.log('DB version changed to '+version);
            };
        }
複製程式碼

這樣在建立資料庫的時候我們就為其新增了一個名為students的object store,準備一些資料以供新增

var students=[{ 
            id:1001, 
            name:"Byron", 
            age:24 
        },{ 
            id:1002, 
            name:"Frank", 
            age:30 
        },{ 
            id:1003, 
            name:"Aaron", 
            age:26 
        }];


function addData(db,storeName){
            var transaction=db.transaction(storeName,'readwrite'); 
            var store=transaction.objectStore(storeName); 

            for(var i=0;i<students.length;i++){
                store.add(students[i]);
            }
        }


openDB(myDB.name,myDB.version);
        setTimeout(function(){
            addData(myDB.db,'students');
        },1000);
複製程式碼

這樣我們就在students object store裡新增了三條記錄,以id為鍵,在chrome控制檯看看效果

在這裡插入圖片描述

keyGenerate

function openDB (name,version) {
            var version=version || 1;
            var request=window.indexedDB.open(name,version);
            request.onerror=function(e){
                console.log(e.currentTarget.error.message);
            };
            request.onsuccess=function(e){
                myDB.db=e.target.result;
            };
            request.onupgradeneeded=function(e){
                var db=e.target.result;
                if(!db.objectStoreNames.contains('students')){
                    db.createObjectStore('students',{autoIncrement: true});
                }
                console.log('DB version changed to '+version);
            };
        }
複製程式碼

在這裡插入圖片描述
剩下的兩種方式有興趣同學可以自己摸索一下了

查詢資料

可以呼叫object store的get方法通過鍵獲取資料,以使用keyPath做鍵為例

function getDataByKey(db,storeName,value){
            var transaction=db.transaction(storeName,'readwrite'); 
            var store=transaction.objectStore(storeName); 
            var request=store.get(value); 
            request.onsuccess=function(e){ 
                var student=e.target.result; 
                console.log(student.name); 
            };
}
複製程式碼

更新資料

可以呼叫object store的put方法更新資料,會自動替換鍵值相同的記錄,達到更新目的,沒有相同的則新增,以使用keyPath做鍵為例

function updateDataByKey(db,storeName,value){
            var transaction=db.transaction(storeName,'readwrite'); 
            var store=transaction.objectStore(storeName); 
            var request=store.get(value); 
            request.onsuccess=function(e){ 
                var student=e.target.result; 
                student.age=35;
                store.put(student); 
            };
}
複製程式碼

刪除資料及object store

呼叫object store的delete方法根據鍵值刪除記錄

function deleteDataByKey(db,storeName,value){
            var transaction=db.transaction(storeName,'readwrite'); 
            var store=transaction.objectStore(storeName); 
            store.delete(value); 
        }
複製程式碼

呼叫object store的clear方法可以清空object store

function clearObjectStore(db,storeName){
            var transaction=db.transaction(storeName,'readwrite'); 
            var store=transaction.objectStore(storeName); 
            store.clear();
}
複製程式碼

呼叫資料庫例項的deleteObjectStore方法可以刪除一個object store,這個就得在onupgradeneeded裡面呼叫了

if(db.objectStoreNames.contains('students')){ 
                    db.deleteObjectStore('students'); 
}
複製程式碼

最後

這就是關於indexedDB的基本使用方式,很多同學看了會覺得很雞肋,和我們正常自己定義個物件使用沒什麼區別,也就是能儲存在本地罷了,這是因為我們還沒有介紹indexedDB之所以稱為indexed的殺器——索引,這個才是讓indexedDB大顯神通的東西,下篇我們就來看看這個殺器。

相關文章