IndexedDB


一、IndexedDB

1、簡介

  隨着瀏覽器功能增強,許多網站開始將大量數據保存在客戶端,從而減少從服務器獲取數據的操作,提高了響應速度。
  cookie 由於大小不超過 4kb,肯定不合適。
  LocalStorage 大小在 2.5 - 10 M間(不同瀏覽器不同,比如Chrome為 5M),且不提供索引、查找慢,也不合適。
  IndexedDB 就比較合適了,是瀏覽器提供的本地數據庫,它可以被網頁腳本創建和操作。IndexedDB 允許儲存大量數據,提供查找接口,還能建立索引提高查詢效率。

2、特點

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

(2)異步處理。
  IndexedDB 操作時采用異步處理,用戶可以進行其它操作。

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

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


3、相關概念

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

(2)對象倉庫(IDBObjectStore 對象)
  每個數據庫都包含若干對象倉庫。可以理解為一個個數據表。

(3)數據記錄  
  對象倉庫中存儲的即為數據記錄,采用鍵值對保存。其中鍵唯一,值可以為任意類型。

(4)索引(IDBIndex 對象)
  為了提高查詢效率,可以根據數據記錄的主鍵建立索引。

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

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

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

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

4、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("數據庫關閉")
    }
},

 

二、indexedDB常用方法

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

1、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數據庫對象。

 

2、indexedDB.deleteDatabase()

  用於刪除數據庫,是一個異步操作,但會立刻返回一個IDBOpenDBRequest對象。

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

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

 

未完待續。。。


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


免責聲明!

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



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