IndexedDB

1、IndexedDB

一、簡介

  隨着瀏覽器功能加強,許多網站開始將大量數據保存在客戶端,從而減小從服務器獲取數據的操做,提升了響應速度。
  cookie 因爲大小不超過 4kb,確定不合適。
  LocalStorage 大小在 2.5 - 10 M間(不一樣瀏覽器不一樣,好比Chrome爲 5M),且不提供索引、查找慢,也不合適。
  IndexedDB 就比較合適了,是瀏覽器提供的本地數據庫,它能夠被網頁腳本建立和操做。IndexedDB 容許儲存大量數據,提供查找接口,還能創建索引提升查詢效率。javascript

二、特色

(1)採用鍵值對存儲。
  IndexedDB 內部採用對象倉庫(object store)存放數據。全部類型的數據均可以直接存入,包括 JavaScript 對象。對象倉庫中,數據以"鍵值對"的形式保存。html

(2)異步處理。
  IndexedDB 操做時採用異步處理,用戶能夠進行其它操做。vue

(3)支持事務。
  IndexedDB 支持事務,即要麼完成、要麼失敗,不會出現完成一半的狀態。java

(4)存儲空間大、且支持二進制存儲。web


三、相關概念

(1)數據庫(IDBDatabase 對象)
  管理、存儲數據的倉庫。IndexedDB 數據庫有版本的概念。同一個時刻,只能有一個版本的數據庫存在。若是要修改數據庫結構(新增或刪除表、索引或者主鍵),只能經過升級數據庫版本完成。vue-cli

(2)對象倉庫(IDBObjectStore 對象)
  每一個數據庫都包含若干對象倉庫。能夠理解爲一個個數據表。數據庫

(3)數據記錄  
  對象倉庫中存儲的即爲數據記錄,採用鍵值對保存。其中鍵惟一,值能夠爲任意類型。數組

(4)索引(IDBIndex 對象)
  爲了提升查詢效率,能夠根據數據記錄的主鍵創建索引。瀏覽器

(5)事務(IDBTransaction 對象)
  數據記錄的讀寫和刪改,都要經過事務完成。事務對象提供error、abort和complete三個事件,用來監聽操做結果。服務器

(6)操做請求(IDBRequest 對象)

(7)指針( IDBCursor 對象)
  可用於遍歷數據。

(8)主鍵集合(IDBKeyRange 對象)

四、vue使用indexedDB快速入門實例

(1)項目目錄結構
  使用vue-cli建立項目。參考:https://www.cnblogs.com/l-y-h/p/11241503.html

 

 

 (2)完整代碼

此處,我將建立一個  「test」 數據庫, 其中有一個 「person」 表(對象倉庫)

【main.js】
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')



【App.vue】
<template>
    <div>
        <small>添加前請先打開數據庫(如數據庫不存在則執行建立過程)</small><br /><br />
        <button @click="openDB">打開數據庫</button>
        <button @click="deleteDB">刪除數據庫</button><br /><br />
        <button @click="closeDB">關閉數據庫</button><br /><br />
        姓名:<input type="text" id="name" v-model="name"><br />
        年齡:<input type="number" id="age" min=1 v-model="age"><br />
        性別:
        男:<input type="radio" id="man" name="sex" value="male" v-model="sex">
        女:<input type="radio" id="woman" name="sex" value="female" v-model="sex"><br />

        <button @click="add">添加數據</button>
        <button @click="get">獲取數據</button><br /> 
        <button @click="foreach">遍歷數據</button><br /> 
        <button @click="update">更新數據</button><br /> 
        <button @click="remove">刪除數據</button><br /> 
        <button @click="searchFromIndex">根據索引查數據</button><br /> 
    </div>
    <!--App -->
</template>

<script>
    import indexedDB from './indexedDB.js'
    export default {
        data () {
            return {
                name: 'tom',
                age: '12',
                sex: 'male'
            }
        },
        methods: {
            openDB() {
                indexedDB.openDB('test', 'person', 1)
            },

            deleteDB() {
                indexedDB.deleteDB('test')
            },
            
            closeDB() {
                indexedDB.closeDB('test')
            },
            
            add() {
                indexedDB.add('person', {name: this.name, age: this.age, sex: this.sex})
            },
            
            get() {
                indexedDB.get('person')
            },
            
            foreach() {
                indexedDB.foreach('person')
            },
            
            update() {
                indexedDB.update('person', {id: 4, name: this.name, age: this.age, sex: this.sex})
            },
            
            remove() {
                indexedDB.remove('person', 4)
            },
            
            searchFromIndex() {
                indexedDB.searchFromIndex('person', 'name', 'tom')
            }
        }
    }
</script>

<style>

</style>




【indexedDB.js】
// 定義一個全局變量,用於保存數據庫鏈接(開發中應該不會這麼寫,此處只是幫助理解)
let db = null;  
export default {
    // indexedDB兼容
    indexedDB: window.indexedDB || window.webkitindexedDB || window.msIndexedDB || mozIndexedDB,

    // 打開數據庫
    // dbname指的是 數據庫名, version 指的是 版本號
    openDB(dbname, objectStoreName, version) {
        // 獲取當前數據庫版本號
        var version = version || 1

        // 獲取數據庫鏈接,若數據庫不存在,會建立數據庫(異步處理,根據狀況自動觸發下面三個事件)
        var request = this.indexedDB.open(dbname, version)

        // 獲取數據庫鏈接失敗
        request.onerror = function(event) {
            console.log('IndexedDB數據庫打開錯誤')
        }

        // 獲取數據庫鏈接成功 
        request.onsuccess = function(event, callback) {
            db = event.target.result;
            if (callback && (typeof callback === 'function')) {
                callback(db)
            }
            if (db != null) {
                console.log('數據庫打開成功')
            }
        }

        // 建立新的儲存空間(當第一次建立數據庫、或者數據庫版本號變化時會觸發)
        request.onupgradeneeded = function(event) {
            console.log('數據庫版本變化')
            console.log('建立數據庫' + dbname)
            // 拿到數據庫鏈接的結果對象
            db = event.target.result;

            // 判斷當前數據庫中表(對象倉庫)是否存在(注意此處是數據庫的表名,不是數據庫名)
            if (!db.objectStoreNames.contains(objectStoreName)) {
                // 建立對象倉庫,並設置主鍵自增
                var objectStore = db.createObjectStore(objectStoreName, {
                    keyPath: 'id',
                    autoIncrement: true
                })

                // 建立索引(根據須要建立)
                objectStore.createIndex('name', 'name', {
                    unique: false
                })

                objectStore.createIndex('age', 'age', {
                    unique: false
                })

                objectStore.createIndex('sex', 'sex', {
                    unique: false
                })
            }
        }

    },

    // 刪除數據庫
    deleteDB: function(dbname, callback) {
        // 刪除數據庫
        var deleteQuest = this.indexedDB.deleteDatabase(dbname);
        
        // 成功刪除
        deleteQuest.onerror = function() {
            console.log('刪除數據庫出錯' + event.target.message)
        }

        // 刪除失敗 
        deleteQuest.onsuccess = function() {
            if (callback && (typeof callback === 'function')) {
                callback()
            }
            console.log('刪除數據庫成功')
        }
    },

    // 關閉數據庫 
    closeDB: function() {
        if (db != null) {
            db.close()
            db = null
            console.log("數據庫關閉")
        }
    },

    // 添加數據
    // 對象倉庫(表名),傳入的參數
    add: function(objectStoreName, argument) {
        if (db != null) {
            console.log(db)
            
            // 執行事務,添加數據到對象倉庫(表)
            var request = db.transaction([objectStoreName], 'readwrite')
                .objectStore(objectStoreName)
                .add(argument);

            request.onsuccess = function(event) {
                console.log('數據寫入成功');
            };

            request.onerror = function(event) {
                console.log('數據寫入失敗');
            }
        }
    },

    // 獲取數據
    // 對象倉庫(表名)
    get: function(objectStoreName) {
        if (db != null){
            console.log(db)
            
            // 執行事務,從對象倉庫(表)中獲取全部數據
            var request = db.transaction([objectStoreName], 'readwrite')
                .objectStore(objectStoreName).getAll()
            
            // 數據獲取失敗
            request.onerror = function(event) {
                console.log('事務失敗')
            }
            
            //數據獲取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 打印全部數據
                    console.log(request.result)
                } else {
                    console.log('未得到數據記錄')
                }
            };
        }
    },
    
    // 遍歷數據
    // 對象倉庫(表名)
    foreach: function(objectStoreName) {
        if (db != null){
            console.log(db)
            
            // 執行事務,從對象倉庫(表)中獲取全部數據
            var request = db.transaction([objectStoreName], 'readwrite')
                .objectStore(objectStoreName).openCursor()
            
            // 數據獲取失敗
            request.onerror = function(event) {
                console.log('事務失敗')
            }
            
            //數據獲取成功
            request.onsuccess = function(event) {
                let cursor = request.result
                if (cursor) {
                    // 遍歷打印全部數據
                    console.log(cursor)
                    console.log(cursor.key)
                    console.log(cursor.value.name)
                    console.log(cursor.value.age)
                    console.log(cursor.value.sex)
                    cursor.continue()
                } else {
                    console.log('未得到數據記錄')
                }
            };
        }
    },
    
    // 更新數據(若數據存在,則覆蓋以前的數據,若數據不存在,則新增一個值)
    // 對象倉庫(表名)
    update: function(objectStoreName, argument) {
        if (db != null) {
            console.log(db)
            
            // 執行事務,添加數據到對象倉庫(表)
            var request = db.transaction([objectStoreName], 'readwrite')
                .objectStore(objectStoreName)
                .put(argument);

            request.onsuccess = function(event) {
                console.log('數據更新成功');
            };

            request.onerror = function(event) {
                console.log('數據更新失敗');
            }
        }
    },
    
    // 刪除數據(若數據不存在,則不會執行刪除操做)
    // 對象倉庫(表名)
    remove: function(objectStoreName, index) {
        if (db != null){
            console.log(db)
            
            // 執行事務,從對象倉庫(表)中獲取全部數據
            var request = db.transaction([objectStoreName], 'readwrite')
                .objectStore(objectStoreName).delete(index)
            
            // 數據獲取失敗
            request.onerror = function(event) {
                console.log('事務失敗')
            }
            
            //數據獲取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 遍歷打印全部數據
                    console.log(request.result)
                } else {
                    console.log('未得到數據記錄')
                }
            };
        }
    },
    
    // 根據索引查值(若數據不存在,返回一個[]數組)
    // 對象倉庫(表名)
    searchFromIndex: function(objectStoreName, index, data) {
        if (db != null){
            console.log(db)
            
            // 執行事務,從對象倉庫(表)中獲取全部數據
            var request = db.transaction([objectStoreName], 'readonly')
                .objectStore(objectStoreName).index(index).getAll(data)
            
            // 數據獲取失敗
            request.onerror = function(event) {
                console.log('事務失敗')
            }
            
            //數據獲取成功
            request.onsuccess = function(event) {
                if (request.result) {
                    // 遍歷打印全部數據
                    console.log(request.result)
                } else {
                    console.log('未得到數據記錄')
                }
            };
        }
    }
}

(3)截圖:
  step1:初始化頁面。

 

 

   step2:點擊 打開數據庫。

 

 

   step3:點擊添加按鈕

 

 

   step4:改變數據後,再次添加

 

 

   step5:獲取數據(控制檯打印)

 

 

   step6:點擊遍歷數據按鈕

 

 

   

  step7:更新數據
    以更新id=4爲例,此時數據不存在,會新增。

 

 

   當修改數據後,再次更新,則會覆蓋原數據。

 

 

   step8:根據 name 查詢全部 爲 tom 的數據。

 

 

   

  step9:刪除第4條數據(根據主鍵來刪,若主鍵不存在,則不會刪除)。
    先獲取當前數據。

 

 

   執行刪除後,會刪除id=4(id是主鍵)的數據。

 

 

   

  step10:關閉、刪除數據庫
    若先點擊 刪除按鈕,再點擊關閉按鈕,則刪除按鈕會等關閉按鈕執行後再執行。

 

 

   此時,test數據庫被刪除。

 

 

   

(4)建立、打開數據庫
  需使用 indexedDB.open() 方法,返回一個 IDBRequest 對象,並可能觸發三個事件(onsuccess 、onerror、onupgradeneeded )。

【格式:】
    var request = window.indexedDB.open(databaseName, version);

【其中:】
    databaseName :爲字符串,表示數據庫名,不可省略。
    version : 爲當前數據庫版本,當數據庫不存在時,會建立數據庫,且默認爲1。
        當數據庫存在時,若 version 大於當前數據庫版本,則會觸發數據庫升級操做。
        當version 省略時,默認爲當前數據庫版本。
        
【可能會觸發的事件】
    onsuccess 表示成功打開數據庫。
    onerror  表示打開數據庫失敗。
    onupgradeneeded  表示數據庫升級事件。當數據庫不存在,或者數據庫指定版本號大於當前版本時觸發。
    
    
【代碼:】
// 打開數據庫
// dbname指的是 數據庫名, version 指的是 版本號
openDB(dbname, objectStoreName, version) {
    // 獲取當前數據庫版本號
    var version = version || 1

    // 獲取數據庫鏈接,若數據庫不存在,會建立數據庫(異步處理,根據狀況自動觸發下面三個事件)
    var request = this.indexedDB.open(dbname, version)

    // 獲取數據庫鏈接失敗
    request.onerror = function(event) {
        console.log('IndexedDB數據庫打開錯誤')
    }

    // 獲取數據庫鏈接成功 
    request.onsuccess = function(event, callback) {
        db = event.target.result;
        if (callback && (typeof callback === 'function')) {
            callback(db)
        }
        if (db != null) {
            console.log('數據庫打開成功')
        }
    }

    // 建立新的儲存空間(當第一次建立數據庫、或者數據庫版本號變化時會觸發)
    request.onupgradeneeded = function(event) {
        console.log('數據庫版本變化')
        console.log('建立數據庫' + dbname)
        // 拿到數據庫鏈接的結果對象
        db = event.target.result;

        // 判斷當前數據庫中表(對象倉庫)是否存在(注意此處是數據庫的表名,不是數據庫名)
        if (!db.objectStoreNames.contains(objectStoreName)) {
            // 建立對象倉庫,並設置主鍵自增
            var objectStore = db.createObjectStore(objectStoreName, {
                keyPath: 'id',
                autoIncrement: true
            })

            // 建立索引(根據須要建立)
            objectStore.createIndex('name', 'name', {
                unique: false
            })

            objectStore.createIndex('age', 'age', {
                unique: false
            })

            objectStore.createIndex('sex', 'sex', {
                unique: false
            })
        }
    }

}

 

(5)添加數據
  向對象倉庫(表)中寫入數據記錄。須要經過事務完成。
  注意:

    db以前已經聲明過全局了,這裏直接用(實際開發中應該不容許直接聲明,能夠經過回調函數來實現,有時間再補充)。
  建立一個事務須要根據 對象倉庫名(表名)以及操做模式(readwrite, readonly),建立事務後,經過IDBTransaction.objectStore(name)方法,拿到 IDBObjectStore 對象,再經過表格對象的add()方法,向表格寫入一條記錄。

// 添加數據
// 對象倉庫(表名),傳入的參數
add: function(objectStoreName, argument) {
    if (db != null) {
        console.log(db)
        
        // 執行事務,添加數據到對象倉庫(表)
        var request = db.transaction([objectStoreName], 'readwrite')
            .objectStore(objectStoreName)
            .add(argument);

        request.onsuccess = function(event) {
            console.log('數據寫入成功');
        };

        request.onerror = function(event) {
            console.log('數據寫入失敗');
        }
    }
},

 

(6)讀取數據
  須要事務來操做。
  能夠objectStore.get(index)、objectStore.getAll()方法用於讀取數據,參數index是主鍵的值。

// 獲取數據
// 對象倉庫(表名)
get: function(objectStoreName) {
    if (db != null){
        console.log(db)
        
        // 執行事務,從對象倉庫(表)中獲取全部數據
        var request = db.transaction([objectStoreName], 'readwrite')
            .objectStore(objectStoreName).getAll()
        
        // 數據獲取失敗
        request.onerror = function(event) {
            console.log('事務失敗')
        }
        
        //數據獲取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 打印全部數據
                console.log(request.result)
            } else {
                console.log('未得到數據記錄')
            }
        };
    }
},

 

(7)遍歷數據
  須要事務來操做。
  遍歷數據表格的全部記錄,要使用指針對象 IDBCursor,使用objectStore.openCursor()獲取。

// 遍歷數據
// 對象倉庫(表名)
foreach: function(objectStoreName) {
    if (db != null){
        console.log(db)
        
        // 執行事務,從對象倉庫(表)中獲取全部數據
        var request = db.transaction([objectStoreName], 'readwrite')
            .objectStore(objectStoreName).openCursor()
        
        // 數據獲取失敗
        request.onerror = function(event) {
            console.log('事務失敗')
        }
        
        //數據獲取成功
        request.onsuccess = function(event) {
            let cursor = request.result
            if (cursor) {
                // 遍歷打印全部數據
                console.log(cursor)
                console.log(cursor.key)
                console.log(cursor.value.name)
                console.log(cursor.value.age)
                console.log(cursor.value.sex)
                cursor.continue()
            } else {
                console.log('未得到數據記錄')
            }
        };
    }
},

 

(8)更新數據
  須要事務來操做。
  使用IDBObjectStore.put(index)方法能夠更新數據,若index存在則覆蓋,不然新增一個值。

// 更新數據(若數據存在,則覆蓋以前的數據,若數據不存在,則新增一個值)
// 對象倉庫(表名)
update: function(objectStoreName, argument) {
    if (db != null) {
        console.log(db)
        
        // 執行事務,添加數據到對象倉庫(表)
        var request = db.transaction([objectStoreName], 'readwrite')
            .objectStore(objectStoreName)
            .put(argument);

        request.onsuccess = function(event) {
            console.log('數據更新成功');
        };

        request.onerror = function(event) {
            console.log('數據更新失敗');
        }
    }
},

 

(9)刪除數據
  須要事務來操做。
  IDBObjectStore.delete(index)方法用於刪除記錄,參數index是主鍵的值。

// 刪除數據(若數據不存在,則不會執行刪除操做)
// 對象倉庫(表名)
remove: function(objectStoreName, index) {
    if (db != null){
        console.log(db)
        
        // 執行事務,從對象倉庫(表)中獲取全部數據
        var request = db.transaction([objectStoreName], 'readwrite')
            .objectStore(objectStoreName).delete(index)
        
        // 數據獲取失敗
        request.onerror = function(event) {
            console.log('事務失敗')
        }
        
        //數據獲取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 遍歷打印全部數據
                console.log(request.result)
            } else {
                console.log('未得到數據記錄')
            }
        };
    }
},

 

(10)使用索引
  須要事務來操做。
  根據創建的索引能夠很方便的查值。IDBObjectStore.index(index)方法用於索引查找,參數index是索引的值。

// 根據索引查值(若數據不存在,返回一個[]數組)
// 對象倉庫(表名)
searchFromIndex: function(objectStoreName, index, data) {
    if (db != null){
        console.log(db)
        
        // 執行事務,從對象倉庫(表)中獲取全部數據
        var request = db.transaction([objectStoreName], 'readonly')
            .objectStore(objectStoreName).index(index).getAll(data)
        
        // 數據獲取失敗
        request.onerror = function(event) {
            console.log('事務失敗')
        }
        
        //數據獲取成功
        request.onsuccess = function(event) {
            if (request.result) {
                // 遍歷打印全部數據
                console.log(request.result)
            } else {
                console.log('未得到數據記錄')
            }
        };
    }
}

 

(11)刪除數據庫(會等事務結束再執行)

// 刪除數據庫
deleteDB: function(dbname, callback) {
    // 刪除數據庫
    var deleteQuest = this.indexedDB.deleteDatabase(dbname);
    
    // 成功刪除
    deleteQuest.onerror = function() {
        console.log('刪除數據庫出錯' + event.target.message)
    }

    // 刪除失敗 
    deleteQuest.onsuccess = function() {
        if (callback && (typeof callback === 'function')) {
            callback()
        }
        console.log('刪除數據庫成功')
    }
},

 

(12)關閉數據庫

// 關閉數據庫 
closeDB: function() {
    if (db != null) {
        db.close()
        db = null
        console.log("數據庫關閉")
    }
},

 

2、indexedDB經常使用方法

  瀏覽器原生提供indexedDB對象,做爲開發者的操做接口。

一、indexedDB.open()

  用於打開數據庫。是一個異步操做,可是會當即返回一個IDBOpenDBRequest 對象。

打開一個名爲test、版本爲1的數據庫。若是該數據庫不存在,則會新建該數據庫。
var openRequest = window.indexedDB.open('test', 1);

觸發事件:
    success:打開成功。
    error:打開失敗。
    upgradeneeded:第一次打開該數據庫,或者數據庫版本發生變化。

在success中,能夠經過openRequest.result屬性拿到已經打開的IndexedDB數據庫對象。
在upgradeneeded中,能夠傳入event,經過 event.target.result 拿到已經打開的IndexedDB數據庫對象。

 

二、indexedDB.deleteDatabase()

  用於刪除數據庫,是一個異步操做,但會馬上返回一個IDBOpenDBRequest對象。

刪除名爲test的數據庫。若數據庫不存在,不會報錯。
var DBDeleteRequest = window.indexedDB.deleteDatabase('test');

觸發事件:
    success:刪除成功。
    error:刪除失敗。

 

未完待續。。。

參考地址:  https://wangdoc.com/javascript/bom/indexeddb.html

相關文章
相關標籤/搜索