当前位置: 首页 > news >正文

IndexedDB(概念、基本使用、Dexie.js的使用)

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展
📃个人状态: 研发工程师,现效力于中国工业软件事业
🚀人生格言: 积跬步至千里,积小流成江海
🥇推荐学习:🍍前端面试宝典 🎨100个小功能 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js
🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

文章目录

    • 何为IndexedDB?
    • IndexedDB的基本使用
      • add
      • update
      • get
      • delete
    • Dexie - IndexedDB的极简包装
    • IndexedDB的对比及使用场景
      • 对比
      • 使用场景
    • 总结

何为IndexedDB?

本篇文章的练习demo已放置GitHub。dexie-use-demo · GitHub

IndexedDB 是一种底层 API,用于在客户端存储大量的结构化数据(也包括文件/二进制大型对象(blobs))。该 API 使用索引实现对数据的高性能搜索。虽然 Web Storage 在存储较少量的数据很有用,但对于存储更大量的结构化数据来说力不从心。而 IndexedDB 提供了这种场景的解决方案。(MDN_IndexedDB)

IndexedDB 是一个事务型数据库系统,它是一个基于 JavaScript 的面向对象数据库。IndexedDB 允许你存储和检索用键索引的对象;可以存储结构化克隆算法支持的任何对象。你只需要指定数据库模式,打开与数据库的连接,然后检索和更新一系列事务。

小贴士👨‍🎓 => 什么是事务?
数据库事务是一系列数据库操作(如插入、更新、删除等)的集合,这些操作作为一个不可分割的工作单元执行,确保数据库的完整性和一致性。事务具有原子性、一致性、隔离性和持久性四个基本特性(ACID)。

  • 原子性(Atomicity)‌:事务中的所有操作必须全部完成或全部不执行,确保数据不会因部分操作失败而处于不一致状态。
  • 一致性(Consistency)‌:事务执行前后,数据库需保持一致状态,中间过程对外部不可见。
  • 隔离性(Isolation)‌:多个事务并发执行时,彼此操作互不干扰,防止数据错误。
  • 持久性(Durability)‌:事务提交后,对数据库的修改永久保存,即使系统故障也不会丢失。

可简化IndexedDB使用的相关库: localForage、dexie.js、PouchDB、idb、idb-keyval、JsStore 或者 lovefield。

浏览器-应用-存储 可以看到今天的主角 IndexedDB。接下来,我们一起来推开 IndexedDB 的大门,看看里面的世界。

在这里插入图片描述


IndexedDB的基本使用

GitHub提交记录

我们打开开发者工具,点击 源代码/来源,点击 代码段,点击 新代码段,添加名为 indexedDB 的代码段。

在这里插入图片描述

createObjectStore:IDBDatabase 接口的 createObjectStore() 方法创建并返回一个新的 object store 或 index。此方法接受一个参数作为 store 的名称,也接受一个可选的参数对象让你可以定义重要的可选属性。你可以用这个属性唯一的标识此 store 中的每个对象。因为参数是一个标识符,所以 store 中的每一个对象都应有此属性并保证此属性唯一。

在这里插入图片描述

接下来,我们编写如下代码,创建并打开名为 test 的数据库,并创建名为 user 的对象存储空间,设置 user_id 作为主键。

// 打开名为"test"的IndexedDB数据库,返回一个IDBOpenDBRequest对象
const db = window.indexedDB.open("test");
// 用于存储数据库连接
let connection;// 当数据库版本升级或首次创建时触发的事件
db.onupgradeneeded = (e) => {// 获取数据库连接connection = e.target.result;// 在数据库中创建一个名为'user'的对象存储空间(objectStore)// 设置'user_id'作为主键(keyPath)connection.createObjectStore('user', {keyPath: 'user_id'});
}// 成功时触发的事件
db.onsuccess = (e) => {// 获取数据库连接connection = e.target.result;console.log('connection success');
}// 失败时触发的事件
db.onerror = (e) => {console.log('connection error');
}

此时我们去右键 indexedDB,点击运行即可得到 test 数据库user对象存储空间

在这里插入图片描述

使用 IndexedDB 执行的操作是异步执行的,以免阻塞应用程序。

我们使用 setTimeout 模拟异步操作。

setTimeout(() => {}, 1000)

接下来我们学习如何进行 增删改查,注意我们把相关逻辑写入定时器内(模拟异步)。

更多实例方法(如数量、索引、键等)请参照 IDBObjectStore · MDN

add

IDBTransacation 接口由 IndexedDB API 提供,异步事务使用数据库中的事件对象属性。所有的读取和写入数据均在事务中完成。由 IDBDatabase 发起事务,通过 IDBTransaction 来设置事务的模式(例如:是否只读 readonly 或读写 readwrite),以及通过 IDBObjectStore 来发起一个请求。同时你也可以使用它来中止事务。

IndexedDB API 的 IDBObjectStore 接口表示数据库中的对象存储。对象存储中的记录根据其键值进行排序。这种排序可以实现快速插入、查找和有序检索。

setTimeout(() => {// 创建一个事务,指定要操作的对象存储空间为user,并设置事务模式为读写模式,允许读取和修改数据const tx = connection.transaction('user', 'readwrite');// 获取到 storeconst store = tx.objectStore('user');// addconst addReq = store.add({user_id: '1',user_name: '前端杂货铺'})addReq.onsuccess = () => {console.log('add success');}addReq.onerror = () => {console.log('add error');}
}, 1000)

运行代码段后,我们刷新 test 数据库,即可看到数据已写入。

在这里插入图片描述

update

setTimeout(() => {// 创建一个事务,指定要操作的对象存储空间为user,并设置事务模式为读写模式,允许读取和修改数据const tx = connection.transaction('user', 'readwrite');// 获取到storeconst store = tx.objectStore('user');// updateconst putReq = store.put({user_id: '1',user_name: '前端杂货铺2025'})putReq.onsuccess = () => {console.log('update success');}putReq.onerror = () => {console.log('update error');}
}, 1000)

在这里插入图片描述

get

setTimeout(() => {// 创建一个事务,指定要操作的对象存储空间为user,并设置事务模式为读写模式,允许读取和修改数据const tx = connection.transaction('user', 'readwrite');// 获取到storeconst store = tx.objectStore('user');// getconst getReq = store.get('1');getReq.onsuccess = (e) => {console.log(e.target.result);}getReq.onerror = () => {console.log('get error'); }
}, 1000)

在这里插入图片描述

delete

setTimeout(() => {// 创建一个事务,指定要操作的对象存储空间为user,并设置事务模式为读写模式,允许读取和修改数据const tx = connection.transaction('user', 'readwrite');// 获取到storeconst store = tx.objectStore('user');// deleteconst delReq = store.delete('1');delReq.onsuccess = () => {console.log('delete success');}delReq.onerror = () => {console.log('delete error'); }
}, 1000)

在这里插入图片描述

完整代码:

// 打开名为"test"的IndexedDB数据库,返回一个IDBOpenDBRequest对象
const db = window.indexedDB.open('test');
// 用于存储数据库连接
let connection;// 当数据库版本升级或首次创建时触发的事件
db.onupgradeneeded = (e) => {// 获取数据库连接connection = e.target.result;// 在数据库中创建一个名为'user'的对象存储空间(objectStore)// 设置'user_id'作为主键(keyPath)connection.createObjectStore('user', {keyPath: 'user_id'});
}// 成功时触发的事件
db.onsuccess = (e) => {// 获取数据库连接connection = e.target.result;console.log('connection success');
}// 失败时触发的事件
db.onerror = (e) => {console.log('connection error')
}// 模拟异步操作
setTimeout(() => {// 创建一个事务,指定要操作的对象存储空间为user,并设置事务模式为读写模式,允许读取和修改数据const tx = connection.transaction('user', 'readwrite');// 获取到storeconst store = tx.objectStore('user');// addconst addReq = store.add({user_id: '1',user_name: '前端杂货铺'})addReq.onsuccess = () => {console.log('add success');}addReq.onerror = () => {console.log('add error');}// updateconst putReq = store.put({user_id: '1',user_name: '前端杂货铺2025'})putReq.onsuccess = () => {console.log('update success');}putReq.onerror = () => {console.log('update error');}// getconst getReq = store.get('1');getReq.onsuccess = (e) => {console.log(e.target.result);}getReq.onerror = () => {console.log('get error'); }// deleteconst delReq = store.delete('1');delReq.onsuccess = () => {console.log('delete success');}delReq.onerror = () => {console.log('delete error'); }
}, 1000)

Dexie - IndexedDB的极简包装

Dexie.js 官方文档

项目地址:dexie-use-demo · GitHub

创建并启动项目。

pnpm create vite dexie-use-democd dexie-use-demo
pnpm install
pnpm run dev

安装 dexie。

pnpm install dexie

创建 src/db.ts 文件。

import Dexie, { type EntityTable } from "dexie";// 定义 Friend 接口,表示朋友对象的数据结构
interface Friend {id: number; // 朋友的唯一标识name: string; // 朋友的姓名age: number; // 朋友的年龄
}// 创建 Dexie 数据库实例,并声明 friends 表
const db = new Dexie("FriendsDatabase") as Dexie & {friends: EntityTable<Friend, "id">; // friends 表,主键为 id
};// 定义数据库的版本和表结构
db.version(1).stores({friends: "++id, name, age", // friends 表,id 为自增主键,包含 name 和 age 字段
});// 导出 Friend 类型和 db 实例,供其他模块使用
export type { Friend };
export { db }; // 导出 db 实例

创建 src/components/DBItems.vue 组件,通过 dexie 实现基本的增删改查。

<template><fieldset><legend>DB Items</legend><!-- 输入朋友姓名 --><label>Name:<input v-model="friendName" type="text" /></label><br /><!-- 输入朋友年龄 --><label>Age:<input v-model="friendAge" type="number" /></label><br /><!-- 显示当前操作状态 --><p v-if="status">当前状态:{{ status }}</p><!-- 操作按钮 --><button @click="addFriend">Add Friend</button><button @click="updateFriend">Update Friend Age By Name</button><button @click="deleteFriend">Delete Friend By Name</button><button @click="getFriend">Get Friend By Name</button><button @click="getAllFriends">Get All Friends</button><button @click="clearAllFriends">Clear All Friends</button><!-- 展示朋友列表 --><ul><liv-for="(item, index) in friends"style="list-style-type: none;display: flex;justify-content: space-between;":key="item.id"><span>Name: {{ item.name }}</span><span>Age: {{ item.age }}</span></li></ul></fieldset>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { db, Friend } from "../db";// 响应式变量
const status = ref("");
const friendName = ref("前端杂货铺");
const friendAge = ref(24);
const friends = ref<Friend[]>([]);// 添加朋友
async function addFriend(): Promise<void> {try {const id = await db.friends.add({name: friendName.value,age: friendAge.value,});status.value = `Friend ${friendName.value} successfully added. Got id ${id}`;// 重置输入friendName.value = "前端杂货铺";friendAge.value = 24;} catch (error: unknown) {status.value = `Failed to add ${friendName.value}: ${error instanceof Error ? error.message : error}`;}
}// 更新朋友信息
async function updateFriend(): Promise<void> {try {const count = await db.friends.where("name").equals(friendName.value).modify({ age: friendAge.value });status.value = count? `Friend ${friendName.value} successfully updated.`: `No friend found with name ${friendName.value}.`;} catch (error: unknown) {status.value = `Failed to update ${friendName.value}: ${error instanceof Error ? error.message : error}`;}
}// 删除朋友
async function deleteFriend(): Promise<void> {try {const count = await db.friends.where("name").equals(friendName.value).delete();status.value =count > 0? `Friend ${friendName.value} successfully deleted.`: `No friend found with name ${friendName.value}.`;} catch (error: unknown) {status.value = `Failed to delete ${friendName.value}: ${error instanceof Error ? error.message : error}`;}
}// 查询单个朋友
async function getFriend(): Promise<void> {try {const friend = await db.friends.where("name").equals(friendName.value).first();if (friend) {friends.value = [friend];status.value = `Found friend: ${friend.name}, Age: ${friend.age}`;} else {friends.value = [];status.value = `No friend found with name ${friendName.value}.`;}} catch (error: unknown) {status.value = `Failed to retrieve friend: ${error instanceof Error ? error.message : error}`;}
}// 查询所有朋友
async function getAllFriends(): Promise<void> {try {friends.value = await db.friends.toArray();status.value = `Found ${friends.value.length} friends.`;} catch (error: unknown) {status.value = `Failed to retrieve friends: ${error instanceof Error ? error.message : error}`;}
}// 清空所有朋友
async function clearAllFriends(): Promise<void> {try {await db.friends.clear();friends.value = [];status.value = "All friends cleared.";} catch (error: unknown) {status.value = `Failed to clear friends: ${error instanceof Error ? error.message : error}`;}
}
</script><style scoped>
button {margin: 5px;padding: 5px;background-color: #42b883;color: white;border: none;border-radius: 3px;cursor: pointer;
}
</style>

修改 src/App.vue 组件。

<script setup lang="ts">
import DBItems from "./components/DBItems.vue";
</script><template><h2>前端杂货铺 study IndexedDB</h2><DBItems />
</template><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


IndexedDB的对比及使用场景

对比

在这里插入图片描述

使用场景

  • 离线 Web 应用(PWA):存储用户数据(如邮件、笔记、待办事项),即使离线也能访问和编辑,网络恢复后同步到服务器。示例:Google Docs 离线模式、Notion 本地缓存。

  • 大数据存储与高效查询:存储大量结构化数据(如产品目录、用户数据),并支持 索引查询、排序、分页。示例:电商网站本地缓存商品数据,实现快速筛选。

  • 文件/二进制数据存储:存储 Blob/File(如图片、音频、视频),适用于本地文件管理或编辑器。示例:图片编辑器保存未上传的草稿、PDF 阅读器缓存文档。

  • 事务性操作(如购物车、支付):支持 ACID 事务,适用于需要数据一致性的场景(如库存增减、订单处理)。示例:离线购物车在结算时保证库存正确扣减。

  • 替代 LocalStorage 存储复杂数据:当数据量超过 LocalStorage 限制(5-10MB),或需要存储 对象而非字符串 时,IndexedDB 是更好的选择。

总结

本篇文章我们首先认识了 IndexedDB 主要用于在客户端存储大量的结构化数据。随后我们联系了基本的 增删改查 的使用。最后我们使用了其对应的第三方库 Dexie 进行了增删改查操作。以上内容都比较简单,属于入门内容,如果大家对这方面感兴趣可以继续深究下去,有不少比较底层的 API 供我们学习使用。

学不可以已,我们下篇文章见~

好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!

参考资料:

  1. MDN · IndexedDB:MDN_IndexedDB
  2. 百度 · 百科
  3. DeepSeek:DeepSeek
  4. VS Code · Copilot
  5. Dexie:Dexie官网

在这里插入图片描述


http://www.dtcms.com/a/268469.html

相关文章:

  • 用Python玩转医学影像实时配准:算法揭秘与实战体验
  • 单片机:STM32F103的开发环境搭建
  • Web-API-day2 间歇函数setInterval与事件监听addEvenListener
  • Win11 安装 Visual Studio(保姆教程 - 更新至2025.07)
  • 每天一个前端小知识 Day 23 - PWA 渐进式 Web 应用开发
  • [Java恶补day39] 整理模板·考点六【反转链表】
  • 【C#】MVVM知识点汇总-2
  • 李宏毅genai笔记: post training 和遗忘
  • OneCode UI组件自主设计支持:深入解析对象生命周期、样式模板与事件管理
  • C++中NULL等于啥
  • Denso Create Programming Contest 2025(AtCoder Beginner Contest 413)
  • 多人协同开发时Git使用命令
  • python库 arrow 库的各种案例的使用详解(更人性化的日期时间处理)
  • Docker Model Runner Chat
  • 【网络安全】不要在 XSS 中使用 alert(1)
  • C语言学习(第一天)
  • Python实现优雅的目录结构打印工具
  • 自采集在线电脑壁纸系统源码v2.0 自适应双端
  • c语言中指针深刻且简单的理解
  • 【机器学习笔记Ⅰ】 8 多元梯度下降法
  • mysql的JDBC和连接池
  • 单片机总复习
  • 升级AGP(Android Gradle plugin)和gradle的版本可以提高kapt的执行速度吗
  • CentOS-6与CentOS-7的网络配置IP设置方式对比 笔记250706
  • RSTP 拓扑收敛机制
  • 【人工智能】AI Agent 技术与应用场景解析
  • 【机器学习笔记Ⅰ】9 特征缩放
  • 零基础 “入坑” Java--- 八、类和对象(一)
  • 【HarmonyOS】鸿蒙6 CodeGenie AI辅助编程工具详解
  • Vue2 重写了数组的 7 个变更方法(原理)