柏虎资源网

专注编程学习,Python、Java、C++ 教程、案例及资源

IndexedDB:浏览器端的强大数据库_浏览器建立数据库连接时出错什么意思

IndexedDB 是浏览器内置的非关系型数据库(NoSQL),适合存储大量结构化数据(如离线应用数据、用户配置、缓存等),具有异步操作、支持事务、键值对存储、索引查询等特性。以下是其核心概念及实用方法详解:

一、核心概念

  1. 数据库(Database):IndexedDB 的顶层容器,每个数据库有唯一名称和版本号(版本号为正整数,用于结构升级)。
  2. 对象存储空间(Object Store):类似关系型数据库的 “表”,用于存储数据记录(键值对)。
  3. 事务(Transaction):操作的最小单位,确保一组操作要么全部成功,要么全部失败,保证数据一致性。
  4. 索引(Index):基于对象存储空间中的字段创建,用于快速查询数据(类似数据库索引)。
  5. 游标(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('数据库删除成功');
};

三、实用技巧

  1. 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));
  1. 错误处理:监听事务的 onabort 事件(事务中断时触发):
transaction.onabort = (event) => {
  console.error('事务中断:', event.target.error);
};
  1. 存储限制:不同浏览器对 IndexedDB 存储上限不同(通常与磁盘空间相关),超出限制会触发 QuotaExceededError,需合理清理过期数据。
  2. 离线支持:结合 Service Worker,可实现离线数据读写,提升 PWA(渐进式 Web 应用)体验。

总结

IndexedDB 适合需要在浏览器端存储大量结构化数据的场景,其核心是通过事务操作对象存储空间,配合索引游标实现高效查询。掌握上述方法后,可轻松实现前端数据的持久化管理。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言