IndexedDB

6 阅读2分钟

示例

function initDB(dbName, storeName) {
    let db = null
    const request = window.indexedDB.open('myDB', 1)
    return new Promise((resolve, reject) => {
        request.onsuccess = e => {
            console.log('数据库打开成功会执行')
            db = e.target.result
            resolve(db)
        }

        request.onupgradeneeded = e => {
            console.log('数据库创建和更新会执行')
            // 建立对象仓库来存储数据
            // 1、根据数据的某个字段作为键路径,要求后续数据必须有该字段
            db = e.target.result
            if (!db.objectStoreNames.contains(storeName)) {
                db.createObjectStore(storeName, { keyPath: 'id' })
            }
        }

        request.onerror = error => {
            console.log('数据库打开失败会执行', error)
        }
    })
}

async function aa() {
    const db = await initDB('myDB', 'myStore')
    const storeName = 'myStore'
    // 1、创建事务
    const transaction = db.transaction([ storeName ], 'readwrite');
    // 2、访问对象仓库
    const store = transaction.objectStore(storeName);
    // 3、向仓库添加数据
    // store.add(data);
    return new Promise((resolve, reject) => {
        const res = store.get(1742884986798)
        console.error('res', res)
        store.onsuccess = e => {
            console.log('数据添加成功后触发');
            resolve(res)
        };
        transaction.oncomplete = e => {
            console.log('所有数据添加完毕后触发');
            resolve(res)
        };
        transaction.onerror = error => {
            console.log('数据添加失败后触发');
            resolve(res)
        };
    })
}

aa().then(res => {
    console.log('res1', res.result)
})

// const data = {
// 	id: Date.now(),
// 	name: '张三',
// 	age: 18,
// };

封装

class IndexedDBWrapper {
  /**
   * 构造函数
   * @param {string} dbName - 数据库名称
   * @param {number} dbVersion - 数据库版本
   * @param {Object} storesConfig - 对象存储配置 {storeName: {keyPath, indexes}}
   */
  constructor(dbName, dbVersion, storesConfig) {
    this.dbName = dbName;
    this.dbVersion = dbVersion;
    this.storesConfig = storesConfig;
    this.db = null;
  }

  /**
   * 打开数据库连接
   * @returns {Promise<IDBDatabase>}
   */
  openDatabase() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, this.dbVersion);

      request.onerror = (event) => {
        reject(`数据库打开失败: ${event.target.error}`);
      };

      request.onsuccess = (event) => {
        this.db = event.target.result;
        resolve(this.db);
      };

      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        
        // 创建或升级对象存储
        for (const storeName in this.storesConfig) {
          if (!db.objectStoreNames.contains(storeName)) {
            const { keyPath, autoIncrement } = this.storesConfig[storeName];
            const store = db.createObjectStore(storeName, { 
              keyPath, 
              autoIncrement: autoIncrement || false 
            });

            // 创建索引
            if (this.storesConfig[storeName].indexes) {
              for (const index of this.storesConfig[storeName].indexes) {
                store.createIndex(index.name, index.keyPath, index.options || {});
              }
            }
          }
        }
      };
    });
  }

  /**
   * 添加数据
   * @param {string} storeName - 对象存储名称
   * @param {Object} data - 要添加的数据
   * @returns {Promise<IDBRequest>}
   */
  add(storeName, data) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readwrite');
      const store = transaction.objectStore(storeName);
      const request = store.add(data);

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`添加数据失败: ${event.target.error}`);
    });
  }

  /**
   * 更新数据
   * @param {string} storeName - 对象存储名称
   * @param {Object} data - 要更新的数据
   * @returns {Promise<IDBRequest>}
   */
  put(storeName, data) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readwrite');
      const store = transaction.objectStore(storeName);
      const request = store.put(data);

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`更新数据失败: ${event.target.error}`);
    });
  }

  /**
   * 获取数据
   * @param {string} storeName - 对象存储名称
   * @param {*} key - 主键值
   * @returns {Promise<Object>}
   */
  get(storeName, key) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readonly');
      const store = transaction.objectStore(storeName);
      const request = store.get(key);

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`获取数据失败: ${event.target.error}`);
    });
  }

  /**
   * 获取所有数据
   * @param {string} storeName - 对象存储名称
   * @returns {Promise<Array>}
   */
  getAll(storeName) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readonly');
      const store = transaction.objectStore(storeName);
      const request = store.getAll();

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`获取所有数据失败: ${event.target.error}`);
    });
  }

  /**
   * 删除数据
   * @param {string} storeName - 对象存储名称
   * @param {*} key - 主键值
   * @returns {Promise<IDBRequest>}
   */
  delete(storeName, key) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readwrite');
      const store = transaction.objectStore(storeName);
      const request = store.delete(key);

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`删除数据失败: ${event.target.error}`);
    });
  }

  /**
   * 清空对象存储
   * @param {string} storeName - 对象存储名称
   * @returns {Promise<IDBRequest>}
   */
  clear(storeName) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readwrite');
      const store = transaction.objectStore(storeName);
      const request = store.clear();

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`清空存储失败: ${event.target.error}`);
    });
  }

  /**
   * 通过索引查询数据
   * @param {string} storeName - 对象存储名称
   * @param {string} indexName - 索引名称
   * @param {*} key - 索引键值
   * @returns {Promise<Array>}
   */
  getByIndex(storeName, indexName, key) {
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([storeName], 'readonly');
      const store = transaction.objectStore(storeName);
      const index = store.index(indexName);
      const request = index.getAll(key);

      request.onsuccess = () => resolve(request.result);
      request.onerror = (event) => reject(`索引查询失败: ${event.target.error}`);
    });
  }

  /**
   * 关闭数据库连接
   */
  close() {
    if (this.db) {
      this.db.close();
      this.db = null;
    }
  }

  /**
   * 删除数据库
   * @returns {Promise<void>}
   */
  deleteDatabase() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.deleteDatabase(this.dbName);

      request.onsuccess = () => resolve();
      request.onerror = (event) => reject(`删除数据库失败: ${event.target.error}`);
      request.onblocked = () => reject('数据库被占用,无法删除');
    });
  }
}

使用示例:

  // 配置数据库
const dbConfig = {
  dbName: 'MyDatabase',
  dbVersion: 1,
  storesConfig: {
    users: {
      keyPath: 'id',
      autoIncrement: true,
      indexes: [
        { name: 'nameIdx', keyPath: 'name' },
        { name: 'ageIdx', keyPath: 'age' }
      ]
    },
    products: {
      keyPath: 'productId',
      indexes: [
        { name: 'categoryIdx', keyPath: 'category' }
      ]
    }
  }
};

// 创建实例
const db = new IndexedDBWrapper(
  dbConfig.dbName,
  dbConfig.dbVersion,
  dbConfig.storesConfig
);

// 使用示例
async function exampleUsage() {
  try {
    // 打开数据库
    await db.openDatabase();
    
    // 添加数据
    await db.add('users', { name: 'Alice', age: 25 });
    await db.add('users', { name: 'Bob', age: 30 });
    
    // 获取数据
    const user = await db.get('users', 1);
    console.log('User with id 1:', user);
    
    // 获取所有用户
    const allUsers = await db.getAll('users');
    console.log('All users:', allUsers);
    
    // 通过索引查询
    const usersByName = await db.getByIndex('users', 'nameIdx', 'Alice');
    console.log('Users named Alice:', usersByName);
    
    // 更新数据
    await db.put('users', { id: 1, name: 'Alice Smith', age: 26 });
    
    // 删除数据
    await db.delete('users', 2);
    
  } catch (error) {
    console.error('Error:', error);
  } finally {
    // 关闭连接
    db.close();
  }
}

exampleUsage();