IndexedDB 基礎操作入門

IndexedDB 打開數據庫、建立連接、建表、加索引字段、添加、更新、刪除、查詢等操作介紹。

示例代碼:

/**
 * 1. 鍵值對存儲
 * 內部採用對象倉庫(object store)存放數據,支持所有類型數據的存入。
 * 在數據倉庫中,數據以"鍵值對"的形式保存,數據記錄都有唯一的主鍵(不可重複);
 * 
 * 2. 異步
 * 
 * 3. 支持事務
 * 在一系列操作步驟中,只要有一步失敗,整個事務就會取消,數據庫回滾到事務發生之前。
 * 
 * 4. 同源限制
 * 每一個數據庫對應創建它的域名(只能訪問自身域名下的數據庫)
 * 
 * 5. 存儲空間大
 * 一般不少於250MB
 * 
 * 6. 支持二進制存儲
 * 支持二進制數據(ArrayBuffer, Blob等)
 * 
 * 數據庫:  IDBDatabase 對象
 * 對象倉庫: IDBObjectStore 對象
 * 索引:    IDBIndex 對象
 * 事務:    IDBTransaction 對象
 * 操作請求: IDBRequest 對象
 * 指針:    IDBCursor 對象
 * 主鍵集合: IDBKeyRange 對象
 * 
 * indexedDB數據庫具有版本的概念(同一時刻,只有一個版本的數據庫存在)
 * 每個數據庫包含若干個對象倉庫(object store,類似於關係型數據庫中的表格)
 */

// 數據庫名稱
const databaseName = 'todo-list';
// 默認數據庫版本
const defaultDatabaseVersion = 1;

/**
 * DB instance
 * @type {IDBDatabase}
 */
let db;

// 測試數據
const data = [
  { todo: 'minutes', name: 'a', id: 10 },
  { todo: 'day', name: 'b', id: 3 },
  { todo: 'month', name: 'c', id: 9 },
  { todo: 'year', name: 'd', id: 2019 },
  { todo: 'notified', name: 'e', id: 0 },
];

// 表名
const tableName = 'todos';

/**
 * 打開數據庫請求
 * open(name: string, version?: number | undefined): IDBOpenDBRequest;
 * IDBOpenDBRequest對象所具備的事件:
 * 1. onerror
 * 2. onsuccess
 * 3. onupgradeneeded(數據庫升級事件)
 * 4. onblocked
 */
const DBOpenRequest = window.indexedDB.open(databaseName, defaultDatabaseVersion);

// 數據庫連接請求失敗事件
DBOpenRequest.addEventListener('error', ev => {
  console.log('DBOpenRequest Error: ', ev);
});

// 數據庫連接請求成功事件
DBOpenRequest.addEventListener('success', () => {
  console.info('連接成功!');
  db = DBOpenRequest.result;
});

// 在當一個數據庫的版本比已經存在的版本還高的時候觸發
DBOpenRequest.addEventListener('upgradeneeded', ev => {
  db = ev.target.result;
  console.log(`版本更新至 ${db.version}`);
  
  db.addEventListener('error', ev => {
    console.log('數據庫加載時出錯', ev);
  });

  // 主鍵
  const keyPath = 'id';
  // 新建表
  let store = null;
  // 如果目標表不存在
  if (!db.objectStoreNames.contains(tableName)) {
    store = db.createObjectStore(tableName, {
      // 表的主鍵
      keyPath,
    });
  }
  // 新建索引字段
  store.createIndex('name', 'name', { unique: false });
  console.info('當前表:', store);
});

/**
 * *初始化現有的數據項*
 */
function initItems(list) {
  for (const item of list) {
    addItem(item);
  }
}
initItems(data);

/**
 * 添加數據項
 */
function addItem(item) {
  const store = db.transaction(tableName, 'readwrite').objectStore(tableName);
  const request = store.add(item);
  request.addEventListener('success', () => {
    console.log('數據寫入成功!');
  });
  request.addEventListener('error', () => {
    console.log('數據寫入失敗!');
  });
}
// addItem({ id: 1, name: 'k', todo: 'link' });

/**
 * 更新單個數據項
 */
function updateItem(item) {
  const store = db.transaction(tableName, 'readwrite').objectStore(tableName);
  const request = store.put(item);
  request.addEventListener('success', () => {
    console.log('數據更新成功!');
  });
  request.addEventListener('error', () => {
    console.log('數據更新失敗!');
  });
}
// updateItem({ id: 1, name: 'j', todo: 'link' });

/**
 * 讀取指定範圍內的數據項列表
 * @param {[(string|number), (string|number)]} range
 * @param {string} idxName 
 */
function readByRange(range, idxName) {
  const transaction = db.transaction(tableName, 'readonly');
  const store = transaction.objectStore(tableName).index(idxName);
  const [start, end] = range;
  // 查詢範圍
  const keyRange = window.IDBKeyRange.bound(start, end);
  // 查詢遊標對象
  const cursor = store.openCursor(keyRange);

  cursor.addEventListener('success', ev => {
    const res = ev.target.result;
    if (!res) {
      console.log('沒有更多數據了!');
      return;
    }
    console.info('條目:', res.value);
    res.continue();
  });
  cursor.addEventListener('error', ev => {
    console.log('範圍查詢失敗:', ev);
  });
}

/**
 * 讀取單個數據項(根據當前索引鍵的特定值)
 */
function readItem(id) {
  const transaction = db.transaction([tableName]);
  const store = transaction.objectStore(tableName);
  const request = store.get(id);

  request.addEventListener('success', () => {
    if (!request.result) {
      console.log('未獲得數據記錄');
      return;
    }
    console.info('id: ' + request.result.id);
    console.info('name: ' + request.result.name);
    console.info('todo: ' + request.result.todo);
  });
  request.addEventListener('error', () => {
    console.log('事務執行失敗!');
  });
}

/**
 * 刪除匹配到的數據項(id值)
 */
function deleteItem(id) {
  const store = db.transaction(tableName, 'readwrite').objectStore(tableName);
  const request = store.delete(id);
  request.addEventListener('success', () => {
    console.log('數據刪除成功!');
  });
  request.addEventListener('error', () => {
    console.log('數據刪除失敗!');
  });
}

/**
 * 查詢所有數據項
 */
function queryAll() {
  const store = db.transaction(tableName, 'readonly').objectStore(tableName);
  const cursor = store.openCursor();
  cursor.addEventListener('success', evt => {
    const res = evt.target.result;
    if (!res) {
      console.log('沒有更多數據了!');
      return;
    }
    console.info('id: ' + res.value.id);
    console.info('name: ' + res.value.name);
    console.info('todo: ' + res.value.todo);
    res.continue();
  });
  cursor.addEventListener('error', () => {
    console.log('查詢結果集失敗!');
  });
}

 

參考:瀏覽器數據庫 IndexedDB 入門教程 - 阮一峯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章