网站首页 > 技术文章 正文
IndexedDB 是浏览器内置的非关系型数据库(NoSQL),适合存储大量结构化数据(如离线应用数据、用户配置、缓存等),具有异步操作、支持事务、键值对存储、索引查询等特性。以下是其核心概念及实用方法详解:
一、核心概念
- 数据库(Database):IndexedDB 的顶层容器,每个数据库有唯一名称和版本号(版本号为正整数,用于结构升级)。
- 对象存储空间(Object Store):类似关系型数据库的 “表”,用于存储数据记录(键值对)。
- 事务(Transaction):操作的最小单位,确保一组操作要么全部成功,要么全部失败,保证数据一致性。
- 索引(Index):基于对象存储空间中的字段创建,用于快速查询数据(类似数据库索引)。
- 游标(Cursor):用于遍历对象存储空间中的数据,支持条件筛选和排序。
二、实用方法与示例
1. 打开 / 创建数据库
使用 indexedDB.open() 方法,返回 IDBOpenDBRequest 对象,通过事件监听处理结果。
// 打开数据库(若不存在则创建)
const request = indexedDB.open('myDB', 1); // 数据库名、版本号
// 数据库版本升级/首次创建时触发(仅版本号提高时执行)
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 若不存在则创建对象存储空间(类似表)
if (!db.objectStoreNames.contains('users')) {
// 创建时需指定键路径(主键),autoIncrement 表示自增
const userStore = db.createObjectStore('users', { keyPath: 'id', autoIncrement: true });
// 创建索引(加速查询,如按用户名查询)
userStore.createIndex('nameIndex', 'name', { unique: false }); // 索引名、字段名、是否唯一
}
};
// 打开成功
request.onsuccess = (event) => {
const db = event.target.result;
console.log('数据库打开成功', db);
// 后续操作(如增删改查)需通过事务
};
// 打开失败
request.onerror = (event) => {
console.error('数据库打开失败', event.target.error);
};
2. 增删改查(CRUD)操作
所有操作必须在事务中执行,事务通过 db.transaction() 创建,支持 readonly(默认)和 readwrite 模式。
(1)添加数据(add)
function addUser(db, userData) {
// 创建事务(指定操作的对象存储空间和模式)
const transaction = db.transaction(['users'], 'readwrite');
const userStore = transaction.objectStore('users');
// 添加数据
const request = userStore.add(userData);
request.onsuccess = () => {
console.log('数据添加成功,主键为:', request.result);
};
request.onerror = () => {
console.error('数据添加失败', request.error);
};
// 事务完成(成功或失败都会触发)
transaction.oncomplete = () => {
console.log('事务完成');
};
}
// 调用示例:添加用户
addUser(db, { name: '张三', age: 25, email: 'zhangsan@example.com' });
(2)查询数据
- 按主键查询(get):
function getUserById(db, id) {
const transaction = db.transaction(['users'], 'readonly');
const userStore = transaction.objectStore('users');
const request = userStore.get(id); // 按主键查询
request.onsuccess = () => {
console.log('查询结果:', request.result); // 若不存在则为 undefined
};
}
// 调用:查询 ID 为 1 的用户
getUserById(db, 1);
- 通过索引查询:
function getUsersByName(db, name) {
const transaction = db.transaction(['users'], 'readonly');
const userStore = transaction.objectStore('users');
const nameIndex = userStore.index('nameIndex'); // 获取索引
// 按索引查询(返回第一个匹配结果)
const request = nameIndex.get(name);
request.onsuccess = () => {
console.log('按姓名查询结果:', request.result);
};
}
// 调用:查询姓名为“张三”的用户
getUsersByName(db, '张三');
- 游标遍历(适合批量查询):
function getAllUsers(db) {
const transaction = db.transaction(['users'], 'readonly');
const userStore = transaction.objectStore('users');
// 打开游标(默认从头遍历所有数据)
const request = userStore.openCursor();
const users = [];
request.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
users.push(cursor.value); // 收集当前数据
cursor.continue(); // 继续下一条
} else {
console.log('所有用户:', users); // 遍历结束
}
};
}
(3)更新数据(put)
put 方法:若主键存在则更新,不存在则新增(类似 “upsert”)。
function updateUser(db, updatedUser) {
const transaction = db.transaction(['users'], 'readwrite');
const userStore = transaction.objectStore('users');
const request = userStore.put(updatedUser); // 需要包含主键(id)
request.onsuccess = () => {
console.log('数据更新成功');
};
}
// 调用:更新 ID 为 1 的用户年龄
updateUser(db, { id: 1, name: '张三', age: 26, email: 'zhangsan@example.com' });
(4)删除数据(delete)
function deleteUser(db, id) {
const transaction = db.transaction(['users'], 'readwrite');
const userStore = transaction.objectStore('users');
const request = userStore.delete(id); // 按主键删除
request.onsuccess = () => {
console.log('数据删除成功');
};
}
// 调用:删除 ID 为 1 的用户
deleteUser(db, 1);
3. 关闭与删除数据库
- 关闭数据库:
db.close(); // 关闭当前数据库连接
- 删除数据库:
const deleteRequest = indexedDB.deleteDatabase('myDB');
deleteRequest.onsuccess = () => {
console.log('数据库删除成功');
};
三、实用技巧
- Promise 封装:IndexedDB 原生使用回调,可封装为 Promise 简化代码:
// 封装打开数据库为 Promise
function openDB(name, version, upgradeCallback) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(name, version);
request.onupgradeneeded = upgradeCallback;
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
// 使用示例
openDB('myDB', 1, (event) => { /* 升级逻辑 */ })
.then(db => { /* 操作数据库 */ })
.catch(err => console.error(err));
- 错误处理:监听事务的 onabort 事件(事务中断时触发):
transaction.onabort = (event) => {
console.error('事务中断:', event.target.error);
};
- 存储限制:不同浏览器对 IndexedDB 存储上限不同(通常与磁盘空间相关),超出限制会触发 QuotaExceededError,需合理清理过期数据。
- 离线支持:结合 Service Worker,可实现离线数据读写,提升 PWA(渐进式 Web 应用)体验。
总结
IndexedDB 适合需要在浏览器端存储大量结构化数据的场景,其核心是通过事务操作对象存储空间,配合索引和游标实现高效查询。掌握上述方法后,可轻松实现前端数据的持久化管理。
猜你喜欢
- 2025-10-02 前端学不动了: Postgres——世界上最先进的开源关系型数据库
- 2024-12-30 SQL.js 开源:在浏览器中运行 SQLite 数据库
你 发表评论:
欢迎- 最近发表
-
- Three.js vs Unity:工业可视化为何选择Web方案?
- 一款全新Redis UI可视化管理工具,支持WebUI和桌面——P3X Redis UI
- 时间线可视化实战:三款AI工具实测,手把手教你制作人生轨迹图
- 【推荐】一款可视化在线 Web 定时任务管理平台,支持秒级任务设置
- 重磅更新!FastDatasets 推出可视化 Web 界面
- 模具设计之UG钣金实例教程(3)_ug钣金基础教程
- 前端基于 RBAC 模型的权限管理实现
- 别再把JWT存在localStorage里了!2025年前端鉴权新思路
- 模具设计之曲面造型中不圆润的曲面如何处理技巧
- 9个专业级别的CSS技巧区分了解和精通的鸿沟
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端路由 (61)
- 前端数组 (73)
- 前端js面试题 (50)
- 前端定时器 (59)
- Oracle RAC (76)
- oracle恢复 (77)
- oracle 删除表 (52)
- oracle 用户名 (80)
- oracle 工具 (55)
- oracle 内存 (55)
- oracle 导出表 (62)
- oracle约束 (54)
- oracle 中文 (51)
- oracle链接 (54)
- oracle的函数 (58)
- oracle面试 (55)
- 前端调试 (52)
本文暂时没有评论,来添加一个吧(●'◡'●)