首頁

目前文章總數:157 篇

  

最後更新:2024年 12月 07日

0004. 前端瀏覽器資料庫 IndexedDB 使用方式

日期:2024年 04月 14日

標籤: JavaScript Html Web IndexedDB Browser

摘要:Frontend


解決問題:如何使用IndexedDB 實現前端建立資料庫資料,並實作新增、修改、刪除資料功能
官網說明手冊:官網連結
Demo範例:連結
基本介紹:本篇分為 6 大部分。
第一部分:介紹 IndexedDB
第二部分:建立資料庫
第三部分:建立索引與查詢
第四部分:新增、修改資料與查詢
第五部分:刪除資料表資料
第六部分:刪除資料庫的方式






第一部分:介紹 IndexedDB

Step 1:是什麼樣的工具

IndexedDB 為用戶端的儲存用 API,可用於大量的結構化資料,並透過索引功能而高效率搜尋資料。
DOM Storage (en-US) 適合儲存較少量的資料;IndexedDB 則適合大量結構化資料的儲存方案。


上述來自官網: MDN(Mozilla Developer Network)
大意:可以幫每個用戶用瀏覽器時建立 Indexed 客戶端資料庫
另外具有以下特性:

1. 非同步事務
2. 可建立索引
3. 客戶端數據庫



Step 2:使用前評估

在使用前應評估以下,如果符合在使用:

項目   說明
靜態離線網站 開發的這個網頁、網站可以離線操作,如一個手冊說明網站
高效搜尋功能 可以將靜態的資料轉為 IndexedDB 資料庫,然後達到快速查詢
減少伺服器負擔 資料為固定的情況下,可以對伺服器取得資料,將資料保存在前端瀏覽器


無論哪種,都是為了資料可重複在瀏覽器上瀏覽,提升效能

Step 3:明顯的缺點

以下是符合評估條件後,要使用前仍會遺留的缺點:

項目   說明
1. 複雜的代碼邏輯 要從手冊中了解整個資料庫生命周期,並且操作皆為非同步,例如要遵守 Onsuccess 的返回後操作等
2. 瀏覽器兼容性 不是所有瀏覽器版本都兼容,使用前需評估用戶群
3. 首次載入耗時 在初始化資料庫階段,會經歷:建庫-> 檢查版本 -> 建索引 -> 建資料 至少 1 秒
4. 儲存空間限制 每個瀏覽器允許儲存的空間不同,但最後仍受限使用者的硬碟空間(包含手機空間)



Step 4:瀏覽器兼容表

以下是截至 2024/03/23 前的 Can I Use 網站記錄資料
如果用戶群是使用 IE 9 以前的瀏覽器,會造成 Javascript 報錯無法使用




第二部分:建立資料庫

Step 1:建立資料庫 - 代碼

基於 Demo範例:連結
有以下代碼:

<button id="createDataBaseButton">1. 建立資料庫</button><br /><br />
const databaseName = "myDatabase";
// 1. 建立資料庫
function createDataBase() {
  // 打開資料庫
  var request = indexedDB.open(databaseName, 1);
  document.getElementById('messageText').innerHTML += "1. 資料庫已建立" + '<br />';      
  // 資料庫版本升級處理
  request.onupgradeneeded = function (event) {
    var db = event.target.result;
    createIndexStruct(db);
  };

  // 資料庫打開成功處理
  request.onsuccess = function (event) {
  };
}


需要注意每當開啟時,會先檢查 request.onupgradeneeded() 版本號,且版本號為整數型態
由 indexedDB.open(databaseName, 1); 觸發,對應 Fucntion 參數

indexedDB.open(使用的資料庫名稱, 版本號)



Step 3:建立資料庫 - 操作DEMO

在 Demo 代碼中,點擊按鈕,產生 IndexedDB 資料庫


Step 4:建立資料庫 - 開發者檢查內容

按下鍵盤F12 開啟開發者模式,可以看到在
應用程式 -> IndexedDB 有建立的資料庫




第三部分:建立索引與查詢

Step 1:建立索引 - 代碼

在建立資料庫時,依照 MDN 的手冊說明,索引應在觸發版本檢查時建立
因此 onupgradeneeded 內建立索引代碼如下:

// 2. 建立資料庫索引
function createIndexStruct(db) {
  // autoIncrement: true  表示自動新增ID
  var objectStore = db.createObjectStore("customers", { autoIncrement: true });
  objectStore.createIndex("name", "name", { unique: false });
  document.getElementById('messageText').innerHTML += "2. 索引已建立" +'<br /><br />';      
}


索引的建立應該依照業務邏輯查詢功能而建立,可參考 MDN 結構化資料庫-索引






第四部分:新增、修改資料與查詢

Step 1:新增資料 - 代碼

基於 Demo範例:連結

<button id="insertRowdataButton">3-1. 新增、修改資料與查詢 - 新增資料</button><br /><br />
const databaseName = "myDatabase";

  // 3. 新增、修改資料與查詢
  function insertRowdata() {
    // 連線資料庫、開啟
    var request = indexedDB.open(databaseName, 1);
    request.onsuccess = function (event) {
      var db = event.target.result;
      // 創建事務並獲取物件存儲區
      var transaction = db.transaction("customers", "readwrite");
      var objectStore = transaction.objectStore("customers");
      // 新增資料      
      var name = 'John';
      var email = "john@example.com";
      var request = objectStore.add({ name: name, email: email });
      request.onsuccess = function (event) {
        document.getElementById('messageText').innerHTML += "3.1 新增資料成功! 資料=> " + '<br />' + "name:" + name  + '<br />' + '   email:' + email  + '<br /><br />';
      };
    };

  }


操作後預期會產生一筆資料,注意資料的結構已從建立資料庫時建立過
因此才能插入 Object 型態的 objectStore.add({ name: name, email: email });

Step 2:新增資料 - 操作DEMO

在 Demo 代碼中,點擊按鈕,產生新增一筆資料


Step 3:新增資料 - 開發者檢查內容

按下鍵盤F12 開啟開發者模式,可以看到資料已建立


Step 4:修改資料 - 代碼

基於 Demo範例:連結

<button id="updateRowdataButton">3-2. 新增、修改資料與查詢 - 修改資料</button><br /><br />
const databaseName = "myDatabase";

// 修改資料
function updateRowdata() {
  // 連線資料庫、開啟
  var request = indexedDB.open(databaseName, 1);
  request.onsuccess = function (event) {
    var db = event.target.result;
    // 創建事務並獲取物件存儲區
    var transaction = db.transaction("customers", "readwrite");
    var objectStore = transaction.objectStore("customers");

    // 取得要修改的資料 - Id = 1的資料
     var getRequest = objectStore.get(1); // 修改此處變數名稱    
    getRequest.onsuccess = function (event) {
      var data = event.target.result;
      if (data) {
        // 修改資料        
        var tempData = data;
        tempData.name = "John Doe";

        // 刪除舊的資料
        objectStore.delete(1);
        var putRequest = objectStore.put(tempData);
        
        putRequest.onsuccess = function (event) {
          document.getElementById('messageText').innerHTML += "3.2 修改資料成功! 修改的資料=> " + '<br />' + " name:" + data.name  + '<br /><br />';
        };
      }
    };
  }
}


IndexedDB 如果要修改資料,需要將舊的資料刪除,然後插入,才可視為修改。
因為在 IndexedDB 中,一但數據存儲,主鍵是不可以變更。所以無法直接透過主鍵來更新資料。

Step 5:修改資料 - 操作DEMO

在 Demo 代碼中,點擊按鈕,修改資料


Step 6:修改資料 - 開發者檢查內容

按下鍵盤F12 開啟開發者模式,可以看到資料修改提示


Step 7:查詢資料 - 代碼

基於 Demo範例:連結

<button id="queryRowdataButton">3-3. 新增、修改資料與查詢 - 查詢資料</button><br /><br />
const databaseName = "myDatabase";

// 查詢資料
function queryRowdata() {
        // 連線資料庫、開啟
        var request = indexedDB.open(databaseName, 1);
        request.onsuccess = function (event) {
          var db = event.target.result;

          // 創建讀取事務並獲取物件存儲區
          var transaction = db.transaction(["customers"], "readonly");
          var objectStore = transaction.objectStore("customers");

          // 取得資料 - 所有資料的取法
          var requestGet = objectStore.getAll();

          // 查詢資料
          requestGet.onsuccess = function (event) {
            var customers = event.target.result;
            document.getElementById('messageText').innerHTML += "3.3 查詢結果:"+ '<br />' ;
            if (customers && customers.length > 0) {
              customers.forEach(function (customer) {
                document.getElementById('messageText').innerHTML += "name:" + customer.name  + '<br />' + '   email:' + customer.email + '<br /><br />';
              });
            } else {
            document.getElementById('messageText').innerHTML += "查無資料" + '<br /><br />';
          }
        };
      }
    }


查詢資料這邊使用的 getAll() 將所有資料取出,常用的有以下:

項目   說明
getAll() 所有資料
get(1) 取得主鍵 Id 為 1 的資料
getAllKeys() 取得所有 [主鍵]
openCursor() 遍歷每筆資料



Step 8:查詢資料 - 操作DEMO

在 Demo 代碼中,點擊按鈕,查詢顯示結果




第五部分:刪除資料表資料

Step 1:刪除資料 - 代碼

基於 Demo範例:連結

<button id="deleteRowdataButton">3-4. 新增、修改資料與查詢 - 刪除資料</button><br /><br />
const databaseName = "myDatabase";

  // 3. 刪除資料
  function deleteRowdata() {
    // 打開數據庫連接
    var request = indexedDB.open(databaseName, 1);

    request.onsuccess = function (event) {
      var db = event.target.result;

      // 創建讀取事務並獲取物件存儲區
      var transaction = db.transaction("customers", "readwrite");
      var objectStore = transaction.objectStore("customers");
      
      // 刪除資料 - 示意用:因為修改後,會產生一筆資料因此要刪除2
      var requestDelete = objectStore.delete(2);
      requestDelete.onsuccess = function (event) {
        document.getElementById('messageText').innerHTML += "3.4 刪除1筆資料成功!"  + '<br /><br />';
      };
    };     
  }


刪除資料則只有 2 種,如果要全刪除要透過 Cursor 一筆筆刪除

項目   說明
delete(1) 刪除主鍵 Id 為 1 的資料
openCursor() 先取得,然後遍歷每筆資料,執行 .delete(); 方法



Step 2:刪除資料 - 操作DEMO

在 Demo 代碼中,點擊按鈕,刪除 1 筆資料


Step 3:刪除資料 - 開發者檢查內容

按下鍵盤F12 開啟開發者模式,可以看到資料已刪除




第六部分:刪除資料庫的方式

Step 1:刪除資料庫 - 代碼

基於 Demo範例:連結

<button id="insertRowdataButton">4. 刪除資料庫</button><br /><br />
const databaseName = "myDatabase";

//4. 刪除資料庫
function emptyDatabase() {      
  var deleteRequest = indexedDB.deleteDatabase(databaseName);
  deleteRequest.onsuccess = function () {
    document.getElementById('messageText').innerHTML += "4. 資料庫已刪除" + '<br /><br />';      
  };
  deleteRequest.onerror = function () {
    document.getElementById('messageText').innerHTML += "4. 資料庫無法刪除" + '<br /><br />';      
  };
}


刪除整個庫相對容易,只要刪除正確名稱的庫[名稱]擊可

Step 2:刪除資料庫 - 操作DEMO

在 Demo 代碼中,點擊按鈕,刪除資料庫


Step 3:新增資料 - 開發者檢查內容

按下鍵盤F12 開啟開發者模式,資料庫 “myDatabase” 完全不在了