indexedDB 基本使用

發表於2017-12-14

indexedDB簡介:

indexedDB 是一種使用瀏覽器儲存大量資料的方法.它創造的資料可以被查詢,並且可以離線使用.

 

indexedDB 有以下特點:
  1. indexedDBWebSQL 資料庫的取代品
  2. indexedDB遵循同源協議(只能訪問同域中儲存的資料,而不能訪問其他域的)
  3. API包含非同步API同步API兩種:多數情況下使用非同步API; 同步API必須同 WebWorkers 一起使用, 目前沒有瀏覽器支援同步API
  4. indexedDB 是事務模式的資料庫, 使用 key-value 鍵值對儲存資料
  5. indexedDB 不使用結構化查詢語言(SQL). 它通過索引(index)所產生的指標(cursor)來完成查詢操作

一、使用indexedDB的基本模式

  1. 開啟資料庫並且開始一個事務。
  2. 建立一個 objecStore
  3. 構建一個請求來執行一些資料庫操作,像增加或提取資料等。
  4. 通過監聽正確型別的 DOM 事件以等待操作完成。
  5. 在操作結果上進行一些操作(可以在 request 物件中找到)

二、建立、開啟資料庫

indexedDB 存在於全域性物件window上, 它最重要的一個方法就是open方法, 該方法接收兩個引數:

  • dbName // 資料庫名稱 [string]
  • version // 資料庫版本 [整型number]

若是本域下不存在名為DB_NAME的資料庫,則上述程式碼會建立一個名為DB_NAME、版本號為VERSION的資料庫; 觸發的事件依次為: upgradeneededsuccess.

若是已存在名為DB_NAME的資料庫, 則上述程式碼會開啟該資料庫; 只觸發success/error事件,不會觸發upgradeneeded事件. db是對該資料庫的引用.

三、建立物件儲存空間和索引

在關係型資料庫(如mysql)中,一個資料庫中會有多張表,每張表有各自的主鍵、索引等;

key-value型資料庫(如indexedDB)中, 一個資料庫會有多個物件儲存空間,每個儲存空間有自己的主鍵、索引等;

建立物件儲存空間的操作一般放在建立資料庫成功回撥裡:

create-database-web

onupgradeneeded 是我們唯一可以修改資料庫結構的地方。在這裡面,我們可以建立和刪除物件儲存空間以及構建和刪除索引。

在資料庫物件database上,有以下方法可供呼叫:

  1. createObjectStore(storeName, configObj) 建立一個物件儲存空間
    • storeName // 物件儲存空間的名稱 [string]
    • configObj // 該物件儲存空間的配置 [object] (其中的keyPath屬性值,標誌物件的該屬性值唯一)
  2. createIndex(indexName, objAttr, configObj) 建立一個索引
    • indexName // 索引名稱 [string]
    • objAttr // 物件的屬性名 [string]
    • configObj // 該索引的配置物件 [object]

四、增加和刪除資料

對資料庫的操作(增刪查改等)都需要通過事務來完成,事務具有三種模式:

  • readonly 只讀(可以併發進行,優先使用)
  • readwrite 讀寫
  • versionchange 版本變更

向資料庫中增加資料

前面提到,增加資料需要通過事務事務的使用方式如下:

insert-data-web資料庫物件的transaction()方法接收兩個引數:

  • storeNames // 物件儲存空間,可以是物件儲存空間名稱的陣列,也可以是單個物件儲存空間名稱,必傳 [array|string]
  • mode // 事務模式,上面提到的三種之一,可選,預設值是readonly [string]

這樣,我們得到一個事務物件transaction, 有三種事件可能會被觸發: complete, error, abort. 現在,我們通過事務向資料庫indexedDB-test的 物件儲存空間movies中插入資料:

delete-data

通過事務物件transaction,在objectStore()方法中指定物件儲存空間,就得到了可以對該物件儲存空間進行操作的物件objectStore.

向資料庫中增加資料,add()方法增加的物件,若是資料庫中已存在相同的主鍵,或者唯一性索引的鍵值重複,則該條資料不會插入進去;

增加資料還有一個方法: put(), 使用方法和add()不同之處在於,資料庫中若存在相同主鍵或者唯一性索引重複,則會更新該條資料,否則插入新資料。

從資料庫中刪除資料

刪除資料使用delete方法,同上類似:

 

從資料中獲取資料

獲取資料使用get方法,同上類似:

五、使用索引

在前面,我們建立了兩個索引alttitle, 配置物件裡面的unique屬性標誌該值是否唯一

現在我們想找到alt屬性值為https://movie.douban.com/subject/26639033/的物件,就可以使用索引。

get-data-by-index

使用唯一性索引,我們可以得到唯一的一條資料(或者undefined),那麼使用非唯一性索引呢?
我們向資料庫中插入一條資料,使title重複:

使用索引title獲取title值為尋夢環遊記的物件:

get-data-by-index-not-unique-web

我們得到的是鍵值最小的那個物件.

使用一次索引,我們只能得到一條資料; 如果我們需要得到所有title屬性值為尋夢環遊記的物件,我們可以使用遊標.

六、使用遊標

得到一個可以操作遊標的請求物件有兩個方法:

  • openCursor(keyRange, direction)
  • openKeyCursor(keyRange, direction)
    這兩個方法接收的引數一樣, 兩個引數都是可選的: 第一個引數是限制值得範圍,第二個引數是指定遊標方向

遊標的使用有以下幾處:

  • 在物件儲存空間上使用: var cursor = objectStore.openCursor()
  • 在索引物件上使用: var cursor = index.openCursor()

在物件儲存空間上使用遊標

使用遊標常見的一種模式是獲取物件儲存空間上的所有資料.

get-data-by-cursor

使用遊標時,需要在成功回撥裡拿到result物件,判斷是否取完了資料:若資料已取完,resultundefined; 若未取完,則result是個IDBCursorWithValue物件,需呼叫continue()方法繼續取資料。 也可以根據自己需求, 對資料進行過濾。

indexedDB2規範中,在物件儲存空間物件上納入了一個getAll()方法,可以獲取所有物件:

在索引上使用遊標

接著本文上述使用索引的例子,在索引title上使用openCursor()方法時,若不傳引數,則會遍歷所有資料,在成功回撥中的到的result物件有以下屬性:

  • key 資料庫中這條物件的title屬性值
  • primaryKey 資料庫中這條物件的alt
  • value 資料庫中這條物件
  • direction openCursor()方法傳入的第二個物件,預設值為next
  • source IDBIndex物件 舉例如下:

    get-data-by-inde-cursor

在索引title上使用openKeyCursor()方法,若不傳引數,同樣也會遍歷所有資料,result物件屬性如下:

  • key 資料庫中這條物件的title屬性值
  • primaryKey 資料庫中這條物件的alt
  • direction openCursor()方法傳入的第二個物件,預設值為next
  • source altBIndex物件

openCursor()方法相比,得到的資料少一個value屬性,是沒有辦法得到儲存物件的其餘部分

前面說到,我們要根據索引title獲取所有title屬性值為尋夢環遊記的物件,要使用遊標,而又不想遍歷所有資料,這時就要用到openCursor()的第一個引數: keyRange

keyRange是限定遊標遍歷的資料範圍,通過IDBKeyRange的一些方法設定該值:

get-data-by-inde-cursor

IDBKeyRange其他一些方法:

更多請參考 MDN|IDBKeyRange

遊標預設遍歷方向是按主鍵從小到大,有時候我們倒序遍歷,此時可以給openCursor()方法傳遞第二個引數: direction: next|nextunique|prev|prevunique

傳了prev的結果是按倒序遍歷的.

因為 “name” 索引不是唯一的,那就有可能存在具有相同 name 的多條記錄。 要注意的是這種情況不可能發生在物件儲存空間上,因為鍵必須永遠是唯一的。 如果你想要在遊標在索引迭代過程中過濾出重複的,你可以傳遞 nextunique(或prevunique, 如果你正在向後尋找)作為方向引數。 當 nextunique 或是 prevunique 被使用時,被返回的那個總是鍵最小的記錄。

get-one-data-unique-cursor

七、關閉和刪除資料庫

  • 關閉資料庫只需要在資料庫物件db上呼叫close()方法即可

    關閉資料庫後,db物件仍然儲存著該資料庫的相關資訊,只是無法再開啟事務(呼叫開啟事務方法會報錯,提示資料庫連線已斷開):

close-database

  • 刪除資料庫則需要使用indexedDB.deleteDatabase(dbName)方法

八、indexedDB的侷限性

以下情況不適合使用IndexedDB

  • 全球多種語言混合儲存。國際化支援不好。需要自己處理。
  • 和伺服器端資料庫同步。你得自己寫同步程式碼。
  • 全文搜尋。

注意,在以下情況下,資料庫可能被清除:

  • 使用者請求清除資料。
  • 瀏覽器處於隱私模式。最後退出瀏覽器的時候,資料會被清除。
  • 硬碟等儲存裝置的容量到限。
  • 不正確的
  • 不完整的改變.

總結

  1. 使用indexedDB.open(dbName, version)開啟一個資料庫連線
  2. 使用indexedDB.deleteDatabase(dbName)刪除一個資料庫
  3. 在資料庫物件db上使用createObjectStore(storeName, config)建立物件儲存空間
  4. 在物件儲存空間objectStore上使用createIndex(indexName, keyName, config)建立索引
  5. 對資料庫的操作都需要通過事務完成: var transction = db.transaction([storeName], mode)
  6. 資料庫的增刪改查均通過objectStore物件完成,var objectStore = transaction.objectStore(storeName)
  7. 對資料庫資料操作有: add()get()delete()put等方法
  8. 查詢資料可以使用索引: objectStore.index(indexName)
  9. 遍歷和過濾資料可以使用遊標: openCursor(keyRange, direction)

參考連結

相關文章