首页 / HTML5 入门教程 / IndexedDB 客户端数据库

HTML5 入门教程

IndexedDB 客户端数据库

本教程共 110 篇 · 第 89 篇 · 更新于 2026-07-28 · 约 5 分钟阅读

HTML5HTML5 入门教程IndexedDBNoSQL客户端数据库事务

89. IndexedDB 客户端数据库

本节目标:理解 IndexedDB 是什么,知道它和 localStorage 的区别,能写出最基础的打开数据库和增删改查代码。

什么是 IndexedDB

localStorage 存的是字符串键值对,数据量大了就力不从心。IndexedDB 是浏览器内置的真正的数据库

特点:

  • 键值对存储:可以存对象、数组、文件等复杂数据
  • 事务支持:操作要么全成功要么全失败,数据不会乱
  • 异步 API:不阻塞页面渲染
  • 容量大:一般是可用硬盘空间的百分比,比 localStorage 大得多
  • 支持索引:可以按字段快速查询
Note

IndexedDB 是 NoSQL 数据库,没有 SQL 语句。所有操作通过 JavaScript API 完成。

和 localStorage 对比

对比项localStorageIndexedDB
数据模型键值对(字符串)对象存储
容量~5MB几百MB或更多
API 复杂度简单较复杂
查询能力只能按键查支持索引和范围查询
同步/异步同步异步
适合场景小配置项大量结构化数据

打开(或创建)数据库

const request = indexedDB.open("MyDatabase", 1);

request.onsuccess = function (event) {
  const db = event.target.result;
  console.log("数据库打开成功");
};

request.onerror = function (event) {
  console.error("打开失败", event.target.error);
};

第一个参数是数据库名,第二个是版本号。版本号变化时会触发升级。

创建对象存储和索引

数据库结构在 onupgradeneeded 里定义。类似建表:

request.onupgradeneeded = function (event) {
  const db = event.target.result;

  // 创建"对象存储"(类似表),id 作为主键
  const store = db.createObjectStore("users", { keyPath: "id" });

  // 创建索引,方便按 name 字段查询
  store.createIndex("nameIndex", "name", { unique: false });

  // 唯一索引:email 不能重复
  store.createIndex("emailIndex", "email", { unique: true });
};

添加数据

function addUser(db, user) {
  const transaction = db.transaction(["users"], "readwrite");
  const store = transaction.objectStore("users");

  const request = store.add(user);

  request.onsuccess = function () {
    console.log("添加成功,id:", request.result);
  };

  transaction.onerror = function () {
    console.error("添加失败");
  };
}

// 使用
addUser(db, { id: 1, name: "张三", email: "zhang@example.com" });

查询数据

按主键查:

function getUser(db, id) {
  const transaction = db.transaction(["users"], "readonly");
  const store = transaction.objectStore("users");
  const request = store.get(id);

  request.onsuccess = function () {
    if (request.result) {
      console.log("找到用户:", request.result);
    } else {
      console.log("没找到");
    }
  };
}

按索引查:

function getUserByName(db, name) {
  const transaction = db.transaction(["users"], "readonly");
  const store = transaction.objectStore("users");
  const index = store.index("nameIndex");
  const request = index.get(name);

  request.onsuccess = function () {
    console.log("查询结果:", request.result);
  };
}

更新和删除

// 更新:put 会覆盖同名主键的记录
function updateUser(db, user) {
  const transaction = db.transaction(["users"], "readwrite");
  const store = transaction.objectStore("users");
  store.put(user);
}

// 删除
function deleteUser(db, id) {
  const transaction = db.transaction(["users"], "readwrite");
  const store = transaction.objectStore("users");
  store.delete(id);
}

完整示例

下面是一个可以打开浏览器控制台直接试的最小化示例:

// 打开数据库
const request = indexedDB.open("TestDB", 1);

request.onupgradeneeded = function (e) {
  const db = e.target.result;
  db.createObjectStore("books", { keyPath: "id" });
};

request.onsuccess = function (e) {
  const db = e.target.result;

  // 添加一本书
  const tx = db.transaction(["books"], "readwrite");
  tx.objectStore("books").add({ id: 1, title: "HTML5入门", author: "码上学" });

  tx.oncomplete = function () {
    // 查询这本书
    const query = db.transaction(["books"]).objectStore("books").get(1);
    query.onsuccess = function () {
      console.log(query.result); // {id: 1, title: "HTML5入门", author: "码上学"}
    };
  };
};
Tip

IndexedDB 的 API 基于事件(event-based),不是 Promise。新手容易陷入回调地狱。实际项目中可以用 idb 这样的轻量库,它把 IndexedDB 包装成了 Promise 风格,好用很多。

适用场景

  • 离线应用:数据存在本地,断网也能用
  • 缓存大量数据:比如文章列表、商品信息
  • 存储文件/Blob:可以直接存图片、音视频的 Blob 对象
  • 需要复杂查询:按日期范围、价格区间等条件筛选数据
Warning

IndexedDB API 比较原始,新手可能觉得繁琐。如果数据量不大,localStorage 够用就别上 IndexedDB。需要复杂操作时考虑用 idbDexie.js 这样的封装库。