當前位置:首頁 > IT技術 > 數據庫 > 正文

indexedDB介紹
2021-09-06 19:21:15

什么是 indexedDB

IndexedDB 是一種使用瀏覽器存儲大量數據的方法.它創(chuàng)造的數據可以被查詢,并且可以離線使用. IndexedDB對于那些需要存儲大量數據,或者是需要離線使用的程序是非常有效的解決方法. --- MDN

??上面是MDN上對于IndexedDB的介紹.其簡單而言,indexedDB就是一個基于事務操作的key-value型數前端數據庫.其API大多是異步的

?

創(chuàng)建一個indexedDB數據庫

const?request?=?indexedDB.open('myDatabase',?1);

request.addEventListener('success',?e?=>?{

????console.log('連接數據庫成功');

});

?

request.addEventListener('error',?e?=>?{

????console.log('連接數據庫失敗');

});

??在上面代碼中我們使用indexedDB.open()創(chuàng)建一個indexedDB數據庫.open()方法接受可以接受兩個參數.第一個是數據庫名,第二個是數據庫的版本號.同時返回一個IDBOpenDBRequest對象用于操作數據庫.其中對于open()的第一個參數數據庫名,open()會先去查找本地是否已有這個數據庫,如果有則直接將這個數據庫返回,如果沒有,則先創(chuàng)建這個數據庫,再返回.對于第二個參數版本號,則是一個可選參數,如果不傳,默認為1.但如果傳入就必須是一個整數.

??在通過對indexedDB.open()方法拿到一個數據庫對象IDBOpenDBRequest我們可以通過監(jiān)聽這個對象的success事件和error事件來執(zhí)行相應的操作.

?

創(chuàng)建一個對象倉庫

??再有了一個數據庫之后,我們獲取就想要去存儲數據了,但是單只有數據庫還不夠,我們還需要有對象倉庫(object store).對象倉庫(object store)是indexedDB數據庫的基礎,其類似于MySQL中表的概念.

要創(chuàng)建一個對象倉庫必須在upgradeneeded事件中,而upgradeneeded事件只會在版本號更新的時候觸發(fā).這是因為indexedDB API中不允許數據庫中的數據倉庫在同一版本中發(fā)生變化

const?request?=?indexedDB.open('myDatabase',?2);

request.addEventListener('upgradeneeded',?e?=>?{

????const?db?=?e.target.result;

????const?store?=?db.createObjectStore('Users',?{

????????keyPath:?'userId',

????????autoIncrement:?false

????});

????console.log('創(chuàng)建對象倉庫成功');

});

??在上述代碼中我們監(jiān)聽upgradeneeded事件,并在這個事件觸發(fā)時使用createObjectStore()方法創(chuàng)建了一個對象倉庫.createObjectStore()方法接受兩個參數,第一個是對象倉庫的名字,在同一數據庫中,倉庫名不能重復.第二個是可選參數.用于指定數據的主鍵,以及是否自增主鍵.

?

創(chuàng)建事務

??OK現在我們有了數據庫和對象倉庫了,我們是否就可以存儲數據了了.很抱歉,還是不行.我們還差最后一樣東西----事務.

?

什么是事務

一個數據庫事務通常包含了一個序列的對數據庫的讀/寫操作。它的存在包含有以下兩個目的

??上面是維基百科上對數據庫事務的解釋.簡單來說事務就是用來保證數據庫操作要么全部成功,要么全部失敗的一個限制.比如,在修改多條數據時,前面幾條已經成功了.,在中間的某一條是失敗了.那么在這時,如果是基于事務的數據庫操作,那么這時數據庫就應該重置前面數據的修改,放棄后面的數據修改.直接返回錯誤,一條數據也不修改.

const?request?=?indexedDB.open('myDatabase',?3);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

});

上述代碼中我們使用transaction()來創(chuàng)建一個事務.transaction()接受兩個參數,第一個是你要操作的對象倉庫名稱,第二個是你創(chuàng)建的事務模式.傳入 readonly時只能對對象倉庫進行讀操作,無法寫操作.可以傳入readwrite進行讀寫操作.

?

操作數據

??好了現在有了數據庫,對象倉庫,事務之后我們終于可以存儲數據了.

  • add() : 增加數據。接收一個參數,為需要保存到對象倉庫中的對象。

  • put() : 增加或修改數據。接收一個參數,為需要保存到對象倉庫中的對象。

  • get() : 獲取數據。接收一個參數,為需要獲取數據的主鍵值。

  • delete() : 刪除數據。接收一個參數,為需要獲取數據的主鍵值。

add 和 put 的作用類似,區(qū)別在于 put 保存數據時,如果該數據的主鍵在數據庫中已經有相同主鍵的時候,則會修改數據庫中對應主鍵的對象,而使用 add 保存數據,如果該主鍵已經存在,則保存失敗。

?

添加數據

const?request?=?indexedDB.open('myDatabase',?3);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

????const?store?=?tx.objectStore('Users');

????const?reqAdd?=?store.add({

????????'userId':?1,

????????'userName':?'李白',

????????'age':?24

????});

????reqAdd.addEventListener('success',?e?=>?{

????????console.log('保存成功')

????})

});

獲取數據

const?request?=?indexedDB.open('myDatabase',?3);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

????const?store?=?tx.objectStore('Users');

????const?reqGet?=?store.get(1);

????reqGet.addEventListener('success',?e?=>?{

????????console.log(this.result.userName);

????})

});

刪除數據

const?request?=?indexedDB.open('myDatabase',?3);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

????const?store?=?tx.objectStore('Users');

????const?reqDelete?=?store.delete(1);

????reqDelete.addEventListener('success',?e?=>?{

????????console.log('刪除數據成功');

????})

});

使用游標

??在上面當中我們使用get()方法傳入一個主鍵來獲取數據,但是這樣只能夠獲取到一條數據.如果我們想要獲取多條數據了怎么辦.我們可以使用游標,來獲取一個區(qū)間內的數據.

??要使用游標,我們需要使用對象倉庫上的openCursor()方法創(chuàng)建幣打開.openCursor()方法接受兩個參數.

openCursor(range?:?IDBKeyRange?|?number?|?string?|?Date?|?IDBArrayKey,?direction?:?IDBCursorDirection):?IDBRequest;

??第一個是范圍,范圍可以是一個IDBKeyRange對象.用以下方式創(chuàng)建.

var?boundRange?=?IDBKeyRange.bound(1,?10,?false,?false);

var?onlyRange?=?IDBKeyRange.only(1);

var?lowerRange?=?IDBKeyRange.lowerBound(1,?false);

var?upperRange?=?IDBKeyRange.upperBound(10,?false);

??第二個參數是方向.主要有一下幾種

next : 游標中的數據按主鍵值升序排列,主鍵值相等的數據都被讀取

nextunique : 游標中的數據按主鍵值升序排列,主鍵值相等只讀取第一條數據

prev : 游標中的數據按主鍵值降序排列,主鍵值相等的數據都被讀取

prevunique : 游標中的數據按主鍵值降序排列,主鍵值相等只讀取第一條數據

??下面讓我們來看一個完整的例子

const?request?=?indexedDB.open('myDatabase',?4);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

????const?store?=?tx.objectStore('Users');

????const?range?=?IDBKeyRange.bound(1,?10);

????const?req?=?store.openCursor(range,?'next');

????req.addEventListener('success',?e?=>?{

????????const?cursor?=?this.result;

????????if?(cursor)?{

????????????console.log(cursor.value.userName);

????????????cursor.continue();

????????}?else?{

????????????console.log('檢索結束');

????????}

????})

});

??在上面的代碼中如果檢索到符合條件的數據時,我們可以:

使用cursor.value拿到數據.

使用cursor.updata()更新數據.

使用cursor.delete()刪除數據.

使用cursor.continue()讀取下一條數據.

索引

??在上面代碼中我們獲取數據都是用的主鍵.但是,在很多情況下我們并不知道我們需要數據的主鍵是什么,我們知道一個大概的條件.比如說年齡大于20歲的用戶.這個時候我們就需要用到索引.以便有條件的查找.

創(chuàng)建索引

??我們使用對象倉庫的createIndex()方法來創(chuàng)建一個索引.

createIndex(name:?string,?keyPath:?string?|?string[],?optionalParameters?:?IDBIndexParameters):?IDBIndex;

createIndex()方法接收三個參數:

  1. 第一個參數name是索引名,不能重復.

  2. 第二個參數keyPath是你要在存儲對象上的那個屬性上建立索引,可以是一個單個的key值,也可以是一個包含key值集合的數組.

  3. 第三個參數optionalParameters是一個可選的對象參數{unique, multiEntry}

  • unique: 用來指定索引值是否可以重復,為true代表不能相同,為false時代表可以相同

  • multiEntry: 當第二個參數keyPath為一個數組時.如果multiEntry是true,則會以數組中的每個元素建立一條索引.如果是false,則以整個數組為keyPath值,添加一條索引.

??下面讓我們來看一個完整的例子,我們建立一條用戶年齡的索引.

const?request?=?indexedDB.open('myDatabase',?5);

request.addEventListener('upgradeneeded',?e?=>?{

????const?db?=?e.target.result;

????const?store?=?db.createObjectStore('Users',?{

????????keyPath:?'userId',

????????autoIncrement:?false

????});

????const?idx?=?store.createIndex('ageIndex',?'age',?{

????????unique:?false

????})

});

??這樣我們就創(chuàng)建了一條索引.

創(chuàng)建索引

??這在創(chuàng)建了一條索引之后我們就可以來使用它了.我們使用對象倉庫上的index方法,通過傳入一個索引名.來拿到一個索引對象.

const?index?=?store.index('ageIndex');`

??然后我們就可以使用這個索引了.比如說我們要拿到年齡在20歲以上的數據,升序排列.

const?request?=?indexedDB.open('myDatabase',?4);

request.addEventListener('success',?e?=>?{

????const?db?=?e.target.result;

????const?tx?=?db.transaction('Users',?'readwrite');

????const?store?=?tx.objectStore('Users');

????const?index?=?store.index('ageIndex');

????const?req?=?index.openCursor(IDBKeyRange.lowerBound(20),?'next');

????req.addEventListener('success',?e?=>?{

????????const?cursor?=?e.target.result;

????????if?(cursor)?{

????????????console.log(cursor.value.age);

????????????cursor.continue();

????????}?else?{

????????????console.log('檢索結束');

????????}

????})

});

indexedDB 的兼容性

?

上面是我對indexedDB一些粗淺的總結,希望對大家有所幫助.如果文中有何不當之處請予以斧正,謝謝.

?

?
?
?
?

本文摘自 :https://blog.51cto.com/u

開通會員,享受整站包年服務立即開通 >