IndexedDB:浏览器端的强大数据库
在现代 Web 开发中,随着应用复杂度的增加,客户端存储的需求也日益增长。现有的存储方案如 Cookie 和 LocalStorage 已经无法满足存储大量数据的需求。这时,IndexedDB 作为一种强大的客户端数据库解决方案应运而生。
一、IndexedDB 简介
IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据。它支持存储包括文件和二进制大型对象(blobs)在内的多种数据类型,并通过索引实现对数据的高性能搜索。与 LocalStorage 相比,IndexedDB 提供了更大的存储空间(通常不少于 250MB,甚至没有上限)和更丰富的功能,如事务支持、异步操作等。
IndexedDB 的主要特点如下:
- 键值对存储:数据以"键值对"的形式保存,每个数据记录都有一个唯一的主键。
- 异步操作:操作不会阻塞浏览器,用户可以继续进行其他操作。
- 事务支持:确保数据操作的原子性,要么全部成功,要么全部失败。
- 存储空间大:存储空间远大于 LocalStorage。
- 支持二进制存储:可以存储二进制数据,如图片、文件等。
二、IndexedDB 的重要概念
在使用 IndexedDB 之前,我们需要了解一些基本概念:
- 数据库:存储数据的容器,每个域名可以创建多个数据库。
- 对象仓库:类似于关系型数据库中的表,用于存储数据记录。
- 数据记录:对象仓库中的数据,包含主键和数据体。
- 索引:加速数据检索的工具,可以为对象仓库中的属性创建索引。
- 事务:用于执行一系列数据操作的机制,确保操作的原子性。
- 指针(游标):用于遍历对象仓库中的数据。
三、IndexedDB 的基本操作
(一)操作数据库
1. 打开数据库
使用 indexedDB.open
方法打开数据库。如果数据库不存在,则会创建一个新的数据库。
javascript
function openDB(dbName, version = 1) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, version);
request.onsuccess = function (event) {
console.log("数据库打开成功");
resolve(event.target.result);
};
request.onerror = function (event) {
console.error("数据库打开失败");
reject(event.target.error);
};
request.onupgradeneeded = function (event) {
console.log("数据库升级");
const db = event.target.result;
const objectStore = db.createObjectStore("stu", { keyPath: "stuId", autoIncrement: true });
objectStore.createIndex("stuName", "stuName", { unique: false });
objectStore.createIndex("stuAge", "stuAge", { unique: false });
};
});
}
2. 关闭数据库
javascript
function closeDB(db) {
db.close();
console.log("数据库已关闭");
}
3. 删除数据库
javascript
function deleteDB(dbName) {
const request = indexedDB.deleteDatabase(dbName);
request.onsuccess = function () {
console.log("数据库删除成功");
};
request.onerror = function (event) {
console.error("数据库删除失败", event.target.error);
};
}
(二)插入数据
javascript
function addData(db, storeName, data) {
const transaction = db.transaction([storeName], "readwrite");
const objectStore = transaction.objectStore(storeName);
const request = objectStore.add(data);
request.onsuccess = function () {
console.log("数据插入成功");
};
request.onerror = function (event) {
console.error("数据插入失败", event.target.error);
};
}
(三)读取数据
1. 通过主键读取数据
javascript
function getDataByKey(db, storeName, key) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], "readonly");
const objectStore = transaction.objectStore(storeName);
const request = objectStore.get(key);
request.onsuccess = function (event) {
console.log("通过主键查询结果", event.target.result);
resolve(event.target.result);
};
request.onerror = function (event) {
console.error("查询失败", event.target.error);
reject(event.target.error);
};
});
}
2. 通过索引读取数据
javascript
function getDataByIndex(db, storeName, indexName, indexValue) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([storeName], "readonly");
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.get(indexValue);
request.onsuccess = function (event) {
console.log("通过索引查询结果", event.target.result);
resolve(event.target.result);
};
request.onerror = function (event) {
console.error("查询失败", event.target.error);
reject(event.target.error);
};
});
}
3. 使用游标遍历数据
javascript
function cursorGetData(db, storeName) {
return new Promise((resolve, reject) => {
const list = [];
const transaction = db.transaction([storeName], "readonly");
const objectStore = transaction.objectStore(storeName);
const request = objectStore.openCursor();
request.onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
list.push(cursor.value);
cursor.continue();
} else {
resolve(list);
}
};
request.onerror = function (event) {
console.error("遍历失败", event.target.error);
reject(event.target.error);
};
});
}
(四)更新数据
javascript
function updateData(db, storeName, data) {
const transaction = db.transaction([storeName], "readwrite");
const objectStore = transaction.objectStore(storeName);
const request = objectStore.put(data);
request.onsuccess = function () {
console.log("数据更新成功");
};
request.onerror = function (event) {
console.error("数据更新失败", event.target.error);
};
}
(五)删除数据
1. 通过主键删除数据
javascript
function deleteDataByKey(db, storeName, key) {
const transaction = db.transaction([storeName], "readwrite");
const objectStore = transaction.objectStore(storeName);
const request = objectStore.delete(key);
request.onsuccess = function () {
console.log("数据删除成功");
};
request.onerror = function (event) {
console.error("数据删除失败", event.target.error);
};
}
2. 通过索引删除数据
javascript
function deleteDataByIndex(db, storeName, indexName, indexValue) {
const transaction = db.transaction([storeName], "readwrite");
const objectStore = transaction.objectStore(storeName);
const index = objectStore.index(indexName);
const request = index.openCursor(IDBKeyRange.only(indexValue));
request.onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
cursor.delete();
cursor.continue();
}
};
request.onerror = function (event) {
console.error("删除失败", event.target.error);
};
}
四、实际应用场景
(一)数据可视化
在数据可视化应用中,需要存储大量的数据,每次请求服务器会消耗大量性能。使用 IndexedDB 可以将数据存储在客户端,提高性能。
(二)即时聊天工具
即时聊天工具需要存储大量的消息,使用 IndexedDB 可以将消息存储在本地,方便用户随时查看历史消息。
(三)存储空间不足时
当 LocalStorage 的存储空间不足时,可以使用 IndexedDB 提供更大的存储空间。