IndexedDB
1. 什么是 IndexedDB?
IndexedDB 是一種 基于瀏覽器的 NoSQL 數據庫,用于存儲大量的結構化數據,包括文件和二進制數據。它比 localStorage
和 sessionStorage
更強大,支持索引查詢、事務等特性。
IndexedDB 主要特點
- 持久存儲:數據存儲在用戶設備上,刷新頁面不會丟失。
- 鍵值對存儲:數據存儲在對象存儲(Object Store)中,使用鍵值對(Key-Value)方式存取。
- 異步 API:IndexedDB 使用 異步操作,不會阻塞主線程。
- 事務管理:支持事務,保證數據一致性。
- 索引支持:允許創建索引,加快查詢速度。
- 可存儲大數據:可以存儲比
localStorage
多得多的數據,可以存儲結構化克隆算法支持的任何對象,文件/二進制大型對象(blobs)。
2. IndexedDB 核心 API
2.1 數據庫管理(Database Management)
IndexedDB 允許創建、打開、升級和刪除數據庫。
獲取所有數據庫列表
刪除指定數據庫
打開或創建數據庫
const request = indexedDB.open("MyDatabase", 1);
MyDatabase
:數據庫名稱。1
:數據庫版本號(升級數據庫時需要增加版本號)。
數據庫打開成功事件
request.onsuccess = function(event) {const db = event.target.result;console.log("數據庫打開成功", db);
};
數據庫升級(創建表)
request.onupgradeneeded = function(event) {const db = event.target.result;if (!db.objectStoreNames.contains("users")) {db.createObjectStore("users", { keyPath: "id", autoIncrement: true });}
};
//改事件會在數據庫第一次創建以及版本號變更時觸發.并且版本號只能遞增只能說整數.
keyPath: "id"
:指定主鍵。名字隨便autoIncrement: true
:自動遞增 ID。
數據庫打開失敗事件
request.onerror = function(event) {console.error("數據庫打開失敗", event.target.errorCode);
};
刪除數據庫
indexedDB.deleteDatabase("MyDatabase").onsuccess = function() {console.log("數據庫刪除成功");
};
注意事項:
- 數據庫的版本號只能 遞增,不能降級。
- 不能在
onsuccess
事件中直接修改數據庫結構,需要在onupgradeneeded
事件中完成。
2.2 事務管理(Transactions)
所有數據庫操作必須在 事務 中完成。
const transaction = db.transaction(["users"], "readwrite");
const store = transaction.objectStore("users");
"readonly"
:只讀事務。"readwrite"
:可讀寫事務。"versionchange"
:用于數據庫升級。
事務事件監聽
transaction.oncomplete = function() {console.log("事務完成");
};
transaction.onerror = function() {console.log("事務出錯", transaction.error);
};
transaction.onabort = function() {console.log("事務被中止");
};
注意事項:
- 事務默認是 自動提交 的,一旦事務完成,不能再操作它。
- 如果某個操作失敗,整個事務都會回滾。
2.3 對象存儲(Object Store)
IndexedDB 的數據存儲在 對象存儲(Object Store) 中,類似于數據庫中的表。
添加數據
store.add({ id: 1, name: "Alice", age: 25 });
更新數據
store.put({ id: 1, name: "Alice", age: 26 });
獲取數據
const request = store.get(1);
request.onsuccess = function() {console.log("用戶數據:", request.result);
};
獲取所有數據
const allRequest = store.getAll();
allRequest.onsuccess = function() {console.log("所有用戶數據:", allRequest.result);
};
刪除數據
store.delete(1);
清空表數據
store.clear();
2.4 索引(Indexes)
索引用于提高查詢性能。
創建索引
store.createIndex("nameIndex", "name", { unique: false });
通過索引查詢數據
const index = store.index("nameIndex");
const request = index.get("Alice");
request.onsuccess = function() {console.log("查詢結果:", request.result);
};
注意事項:
unique: true
表示索引字段值不能重復。
2.5 游標(Cursors)
用于遍歷數據。
const cursorRequest = store.openCursor();
//openCursor()接受兩個可選參數
//要查詢的鍵或者 IDBKeyRange 。如果傳一個有效的鍵,則會默認為只包含此鍵的范圍。如果此參數不傳值,則默認為一個選擇了該對象存儲空間全部記錄的鍵范圍。
//direction IDBCursorDirection 來告訴游標要移動的方向。
//有效的值有 "next" 、"nextunique" 、"prev" 和 "prevunique"。默認值是 "next"。
cursorRequest.onsuccess = function(event) {const cursor = event.target.result;if (cursor) {console.log("遍歷數據:", cursor.value);cursor.continue();}
};
let keyRangeValue = IDBKeyRange.bound(2,6);store.openCursor(keyRangeValue)//查詢id 2~6的
// 倒著查詢
let keyRangeValue = IDBKeyRange.upperBound(5);
store.openCursor(keyRangeValue,'prev')
查詢條件 | 代碼 |
---|---|
所有鍵 ≤ x | IDBKeyRange.upperBound(x) |
所有鍵 < x | IDBKeyRange.upperBound(x, true) |
所有鍵 ≥ y | IDBKeyRange.lowerBound(y) |
所有鍵 > y | IDBKeyRange.lowerBound(y, true) |
所有鍵 ≥ x 且 ≤ y | IDBKeyRange.bound(x, y) |
所有鍵 > x 且 < y | IDBKeyRange.bound(x, y, true, true) |
所有鍵 > x 且 ≤ y | IDBKeyRange.bound(x, y, true, false) |
所有鍵 ≥ x 且 < y | IDBKeyRange.bound(x, y, false, true) |
鍵值等于 z | IDBKeyRange.only(z) |
注意事項:
cursor.continue()
讓游標指向下一個數據。cursor.delete()
可刪除當前項。
3. IndexedDB 完整示例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>IndexedDB 示例</title>
</head><body><script>let arr = Array(10).fill(0).map((_, i) => ({ id: i, name: `用戶${i}`, age: 20 + i }));const request = indexedDB.open("demo", 1);let db;request.onupgradeneeded = function (e) {db = e.target.result;console.log("數據庫升級:", db);if (!db.objectStoreNames.contains("users")) {db.createObjectStore("users", { keyPath: "id", autoIncrement: true });console.log("對象存儲 'users' 創建成功");}};request.onsuccess = function (e) {db = e.target.result;const transaction = db.transaction("users", "readwrite");const store = transaction.objectStore("users");arr.forEach(item => {store.add(item);});store.getAll().onsuccess = function (e) {console.log("所有數據:", e.target.result);};var keyRangeValue = IDBKeyRange.upperBound(5);store.openCursor(keyRangeValue, 'prev').onsuccess = function (e) {const cursor = e.target.result;if (cursor) {console.log("游標數據:", cursor.value);cursor.continue();}};};request.onerror = function (e) {console.error("數據庫打開失敗", e.target.error);};request.onblocked = function () {console.warn("數據庫升級被阻塞,請關閉其他頁面");};</script>
</body></html>
IndexedDB 提供了一系列 API 來管理數據庫、存儲對象和執行事務,以下是 IndexedDB 的所有主要 API,按照功能分類列出:
1. 數據庫管理(Database Management)
這些 API 負責打開、創建和刪除數據庫:
API | 作用 |
---|---|
indexedDB.open(name, version) | 打開數據庫,如果不存在則創建 |
indexedDB.deleteDatabase(name) | 刪除數據庫 |
indexedDB.databases() | 獲取所有已創建的數據庫(僅部分瀏覽器支持) |
IDBOpenDBRequest.onsuccess | 數據庫打開成功的事件 |
IDBOpenDBRequest.onerror | 數據庫打開失敗的事件 |
IDBOpenDBRequest.onupgradeneeded | 數據庫版本變更時觸發(用于初始化或升級數據庫) |
2. 事務(Transactions)
IndexedDB 使用事務來確保數據一致性:
API | 作用 |
---|---|
db.transaction(storeNames, mode) | 創建事務,mode 可以是 "readonly" 或 "readwrite" |
IDBTransaction.objectStore(name) | 獲取對象存儲(表) |
IDBTransaction.oncomplete | 事務成功完成時觸發 |
IDBTransaction.onerror | 事務出錯時觸發 |
IDBTransaction.onabort | 事務被中止時觸發 |
3. 對象存儲(Object Store)
IndexedDB 中的數據存儲在對象存儲(類似數據庫中的表)中:
API | 作用 |
---|---|
db.createObjectStore(name, options) | 創建對象存儲,options 可設置 keyPath |
IDBDatabase.deleteObjectStore(name) | 刪除對象存儲 |
IDBObjectStore.add(value, key?) | 添加數據(如果 keyPath 沒有設置 key ,可以傳 key ) |
IDBObjectStore.put(value, key?) | 更新數據(如果 key 已存在) |
IDBObjectStore.get(key) | 獲取指定 key 的數據 |
IDBObjectStore.getAll() | 獲取所有數據(部分瀏覽器不支持) |
IDBObjectStore.getAllKeys() | 獲取所有 key (部分瀏覽器不支持) |
IDBObjectStore.delete(key) | 刪除指定 key 的數據 |
IDBObjectStore.clear() | 清空整個對象存儲 |
IDBObjectStore.createIndex(name, keyPath, options) | 創建索引 |
IDBObjectStore.index(name) | 獲取索引 |
4. 索引(Indexes)
索引用于加速查詢:
API | 作用 |
---|---|
IDBIndex.get(key) | 通過索引查找數據 |
IDBIndex.getAll() | 獲取所有索引匹配的數據 |
IDBIndex.getAllKeys() | 獲取所有索引的 key |
IDBIndex.count() | 統計匹配索引的數據條數 |
IDBIndex.openCursor() | 通過索引游標遍歷數據 |
5. 游標(Cursors)
游標用于遍歷大數據集:
API | 作用 |
---|---|
IDBObjectStore.openCursor() | 遍歷對象存儲 |
IDBIndex.openCursor() | 通過索引遍歷數據 |
IDBCursor.continue() | 繼續下一個數據項 |
IDBCursor.advance(n) | 跳過 n 個數據項 |
IDBCursor.delete() | 刪除當前游標指向的數據 |
IDBCursor.update(value) | 更新當前游標指向的數據 |
6. 事件(Events)
IndexedDB 主要是基于事件的,以下是常見事件:
事件 | 觸發時機 |
---|---|
onupgradeneeded | 數據庫版本更新時 |
onsuccess | 操作成功時 |
onerror | 操作失敗時 |
oncomplete | 事務完成時 |
onabort | 事務中止時 |
7. 其他 API
一些輔助 API:
API | 作用 |
---|---|
IDBFactory.cmp(key1, key2) | 比較兩個鍵的大小 |
IDBObjectStore.count() | 統計對象存儲中的數據條數 |
總結
IndexedDB 提供了一整套 API 來管理數據庫、對象存儲、索引和事務,核心 API 主要包括:
- 數據庫管理:
indexedDB.open()
、indexedDB.deleteDatabase()
- 事務:
transaction()
、objectStore()
- 對象存儲操作:
add()
、put()
、get()
、delete()
- 索引:
createIndex()
、get()
、openCursor()
- 游標:
openCursor()
、continue()
、advance()
- 事件:
onsuccess
、onerror
、onupgradeneeded