浏览器存储 IndexedDB
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