IndexedDB 教程

IndexedDB 教程

IndexedDB 是一個基於 JavaScript 的面向對象的事務型數據庫。有了 LocalStorage 和 Cookies,爲何還要推出 indexedDB 呢?其實對於在瀏覽器裏存儲數據,可使用 cookies 或 LocalStorage,但它們都是比較簡單的技術,而 IndexedDB 提供了相似數據庫風格的數據存儲和使用方式。javascript

LocalStorage 與 IndexedDB 區別也適用場景

LocalStorage 是用 key-value 鍵值模式存儲數據,它存儲的數據都是字符串形式。若是你想讓 LocalStorage存儲對象,你須要藉助 JSON.stringify()能將對象變成字符串形式,再用 JSON.parse()將字符串還原成對象,就是專門爲小數量數據設計的,因此它的 api 設計爲同步的。html

IndexedDB 很適合存儲大量數據,它的 API 是異步調用的。IndexedDB 使用索引存儲數據,各類數據庫操做放在事務中執行。IndexedDB 甚至還支持簡單的數據類型。IndexedDB 比 localstorage 強大得多,但它的 API 也相對複雜。對於簡單的數據,你應該繼續使用 localstorage,但當你但願存儲大量數據時,IndexedDB 會明顯的更適合,IndexedDB 能提供你更爲複雜的查詢數據的方式。java

indexedDB 的特性

  • 對象倉庫

有了數據庫後咱們天然但願建立一個表用來存儲數據,但 indexedDB 中沒有表的概念,而是 objectStore,一個數據庫中能夠包含多個 objectStore,objectStore 是一個靈活的數據結構,能夠存放多種類型數據。也就是說一個 objectStore 至關於一張表,裏面存儲的每條數據和一個鍵相關聯。咱們可使用每條記錄中的某個指定字段做爲鍵值(keyPath),也可使用自動生成的遞增數字做爲鍵值(keyGenerator),也能夠不指定。選擇鍵的類型不一樣,objectStore 能夠存儲的數據結構也有差別。web

  • 事務性

在 indexedDB 中,每個對數據庫操做是在一個事務的上下文中執行的。事務範圍一次影響一個或多個 object stores,你經過傳入一個 object store 名字的數組到建立事務範圍的函數來定義。例如:db.transaction(storeName, 'readwrite'),建立事務的第二個參數是事務模式。當請求一個事務時,必須決定是按照只讀仍是讀寫模式請求訪問。ajax

  • 基於請求

對 indexedDB 數據庫的每次操做,描述爲經過一個請求打開數據庫,訪問一個 object store,再繼續。IndexedDB API 天生是基於請求的,這也是 API 異步本性指示。對於你在數據庫執行的每次操做,你必須首先爲這個操做建立一個請求。當請求完成,你能夠響應由請求結果產生的事件和錯誤。數據庫

  • 異步

在 IndexedDB 大部分操做並非咱們經常使用的調用方法,返回結果的模式,而是請求—響應的模式,所謂異步 API 是指並非這條指令執行完畢,咱們就可使用 request.result 來獲取 indexedDB 對象了,就像使用 ajax 同樣,語句執行完並不表明已經獲取到了對象,因此咱們通常在其回調函數中處理。api

幾個概念

快速入門 demo

  • 打開數據庫實例。
var db; // 全局的indexedDB數據庫實例。 //1\. 獲取IDBFactory接口實例(文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory) var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; if (!indexedDB) { console.log('你的瀏覽器不支持IndexedDB'); } // 2\. 經過IDBFactory接口的open方法打開一個indexedDB的數據庫實例 // 第一個參數: 數據庫的名字,第二個參數:數據庫的版本。返回值是一個:IDBRequest實例,此實例有onerror和onsuccess事件。 var IDBOpenDBRequest = indexedDB.open('demoDB', 1); // 3\. 對打開數據庫的事件進行處理 // 打開數據庫成功後,自動調用onsuccess事件回調。 IDBOpenDBRequest.onsuccess = function(e) {}; // 打開數據庫失敗 IDBOpenDBRequest.onerror = function(e) { console.log(e.currentTarget.error.message); }; // 第一次打開成功後或者版本有變化自動執行如下事件:通常用於初始化數據庫。 IDBOpenDBRequest.onupgradeneeded = function(e) { db = e.target.result; // 獲取到 demoDB對應的 IDBDatabase實例,也就是咱們的數據庫。 if (!db.objectStoreNames.contains(personStore)) { //若是表格不存在,建立一個新的表格(keyPath,主鍵 ; autoIncrement,是否自增),會返回一個對象(objectStore) // objectStore就至關於數據庫中的一張表。IDBObjectStore類型。 var objectStore = db.createObjectStore(personStore, { keyPath: 'id', autoIncrement: true }); //指定能夠被索引的字段,unique字段是否惟一。類型: IDBIndex objectStore.createIndex('name', 'name', { unique: true }); objectStore.createIndex('phone', 'phone', { unique: false }); } console.log('數據庫版本更改成: ' + dbVersion); }; 
  • 數據庫的 objectStore 添加

indexedDB 的增刪改查的操做須要放到一個事務中進行(推薦)

// 建立一個事務,類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取IDBObjectStore var store = transaction.objectStore(personStore); // 往store表中添加數據 var addPersonRequest = store.add({ name: '老馬', phone: '189111833', address: 'aicoder.com' }); // 監聽添加成功事件 addPersonRequest.onsuccess = function(e) { console.log(e.target.result); // 打印添加成功數據的 主鍵(id) }; // 監聽失敗事件 addPersonRequest.onerror = function(e) { console.log(e.target.error); }; 
  • 數據庫的 objectStore 修改
// 建立一個事務,類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取IDBObjectStore var store = transaction.objectStore(personStore); var person = { id: 6, name: 'lama', phone: '515154084', address: 'aicoder.com' }; // 修改或者添加數據。 第一參數是要修改的數據,第二個參數是主鍵(可省略) var updatePersonRequest = store.get(6); // 監聽添加成功事件 updatePersonRequest.onsuccess = function(e) { // var p = e.target.result; // 要修改的原對象 store.put(person); }; // 監聽失敗事件 updatePersonRequest.onerror = function(e) { console.log(e.target.error); }; 
  • 數據庫的 objectStore 刪除
// 建立一個事務,類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取IDBObjectStore var store = transaction.objectStore(personStore); store.delete(6).onsuccess = function(e) { console.log(刪除成功!) }; 
  • 根據 id 獲取數據
// 建立一個事務,類型:IDBTransaction,文檔地址: https://developer.mozilla.org/en-US/docs/Web/API/IDBTransaction var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取IDBObjectStore var store = transaction.objectStore(personStore); store.get(6).onsuccess = function(e) { console.log(刪除成功!) }; 
  • 數據庫的 objectStore 遊標查詢
var trans = db.transaction(personStore, 'readwrite'); var store = trans.objectStore(personStore); var cursorRequest = store.openCursor(); cursorRequest.onsuccess = function(e) { var cursor = e.target.result; if (cursor) { var html = template('tbTmpl', cursor.value); document.getElementById('tbd').innerHTML += html; cursor.continue(); // 遊標繼續往下 搜索,重複觸發 onsuccess方法,若是到最後返回null } }; 

完整案例

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="./lib/art_template.js"></script> </head> <body> <table> <tr> <td> <label for="name">用戶名</label> </td> <td> <input type="text" name="name" id="name"> </td> </tr> <tr> <td> <label for="phone">電話</label> </td> <td> <input type="text" name="phone" id="phone"> </td> </tr> <tr> <td> <label for="address">地址</label> </td> <td> <input type="text" name="address" id="address"> </td> </tr> </table> <input type="button" value="添加用戶" id="btnAdd" onclick="addPerson()"> <table> <thead> <tr> <th>id</th> <th>name</th> <th>address</th> <th>phone</th> <th>編輯</th> </tr> </thead> <tbody id="tbd"> </tbody> </table> <script id="tbTmpl" type="text/html"> <tr> <td>{{id}}</td> <td>{{name}}</td> <td>{{phone}}</td> <td>{{address}}</td> <td><a href="#">修改</a> <a href="#" onclick="delById({{id}})">刪除</a></td> </tr> </script> <script> var db, dbName = 'demoDb', dbVersion = 1, personStore = 'person'; // 建立indexedDB對象,兼容各類瀏覽器 var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; if (!indexedDB) { console.log("你的瀏覽器不支持IndexedDB"); } openIndexedDB(loadTableData); // 配合遊標遍歷表中數據,並配合art-template生成html function loadTableData() { document.getElementById('tbd').innerHTML = ""; var trans = db.transaction(personStore, 'readwrite'); var store = trans.objectStore(personStore); var cursorRequest = store.openCursor(); cursorRequest.onsuccess = function (e) { var cursor = e.target.result; if (cursor) { var html = template('tbTmpl', cursor.value); document.getElementById('tbd').innerHTML += html; cursor.continue(); // 遊標繼續往下 搜索,重複觸發 onsuccess方法,若是到到返回null } } } function delById(id) { if (!db || !id) { return; } // 建立一個事務 var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取store var store = transaction.objectStore(personStore); // 刪除請求 var delPersonRequest = store.delete(id); delPersonRequest.onsuccess = function (e) { loadTableData(); // 刪除成功後,從新加載數據 } delPersonRequest.onerror = function (e) { console.log(e.target.error); } } // 添加用戶 function addPerson() { if (!db) { return; } var pName = document.getElementById('name').value; var pPhone = document.getElementById('phone').value; var pAddress = document.getElementById('address').value; // 建立一個事務 var transaction = db.transaction(personStore, 'readwrite'); // 經過事務來獲取store var store = transaction.objectStore(personStore); var addPersonRequest = store.add({ name: pName, phone: pPhone, address: pAddress }); addPersonRequest.onsuccess = function (e) { console.log(e.target); loadTableData(); // 添加成功後從新加載數據 } addPersonRequest.onerror = function (e) { console.log(e.target.error); } } // 打開數據庫 function openIndexedDB(callback) { // 打開一個數據庫 var request = indexedDB.open(dbName, dbVersion); // 打開失敗 request.onerror = function (e) { console.log(e.currentTarget.error.message); }; // 打開成功! request.onsuccess = function (e) { db = e.target.result; console.log('成功打開DB'); callback(); }; // 打開成功後,若是版本有變化自動執行如下事件 request.onupgradeneeded = function (e) { var db = e.target.result; if (!db.objectStoreNames.contains(personStore)) { console.log("我須要建立一個新的存儲對象"); //若是表格不存在,建立一個新的表格(keyPath,主鍵 ; autoIncrement,是否自增),會返回一個對象(objectStore) var objectStore = db.createObjectStore(personStore, { keyPath: "id", autoIncrement: true }); //指定能夠被索引的字段,unique字段是否惟一, 指定索引能夠加快搜索效率。 objectStore.createIndex("name", "name", { unique: true }); objectStore.createIndex("phone", "phone", { unique: false }); } console.log('數據庫版本更改成: ' + dbVersion); }; } </script> </body> </html> 

另一個封裝的案例

<!DOCTYPE HTML> <html> <head> <title>aicoder.com</title> </head> <body> <script type="text/javascript"> function openDB(name, version) { var version = version || 1; var request = window.indexedDB.open(name, version); request.onerror = function (e) { console.log(e.currentTarget.error.message); }; request.onsuccess = function (e) { myDB.db = e.target.result; }; request.onupgradeneeded = function (e) { var db = e.target.result; if (!db.objectStoreNames.contains('students')) { var store = db.createObjectStore('students', { keyPath: 'id' }); store.createIndex('nameIndex', 'name', { unique: true }); store.createIndex('ageIndex', 'age', { unique: false }); } console.log('DB version changed to ' + version); }; } function closeDB(db) { db.close(); } function deleteDB(name) { indexedDB.deleteDatabase(name); } function addData(db, storeName) { var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); for (var i = 0; i < students.length; i++) { store.add(students[i]); } } function getDataByKey(db, storeName, value) { var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); var request = store.get(value); request.onsuccess = function (e) { var student = e.target.result; console.log(student.name); }; } function updateDataByKey(db, storeName, value) { var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); var request = store.get(value); request.onsuccess = function (e) { var student = e.target.result; student.age = 35; store.put(student); }; } function deleteDataByKey(db, storeName, value) { var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); store.delete(value); } function clearObjectStore(db, storeName) { var transaction = db.transaction(storeName, 'readwrite'); var store = transaction.objectStore(storeName); store.clear(); } function deleteObjectStore(db, storeName) { var transaction = db.transaction(storeName, 'versionchange'); db.deleteObjectStore(storeName); } function fetchStoreByCursor(db, storeName) { var transaction = db.transaction(storeName); var store = transaction.objectStore(storeName); var request = store.openCursor(); request.onsuccess = function (e) { var cursor = e.target.result; if (cursor) { console.log(cursor.key); var currentStudent = cursor.value; console.log(currentStudent.name); cursor.continue(); } }; } function getDataByIndex(db, storeName) { var transaction = db.transaction(storeName); var store = transaction.objectStore(storeName); var index = store.index("ageIndex"); index.get(26).onsuccess = function (e) { var student = e.target.result; console.log(student.id); } } function getMultipleData(db, storeName) { var transaction = db.transaction(storeName); var store = transaction.objectStore(storeName); var index = store.index("nameIndex"); var request = index.openCursor(null, IDBCursor.prev); request.onsuccess = function (e) { var cursor = e.target.result; if (cursor) { var student = cursor.value; console.log(student.name); cursor.continue(); } } } var myDB = { name: 'test', version: 1, db: null }; var students = [{ id: 1001, name: "Byron", age: 24 }, { id: 1002, name: "Frank", age: 30 }, { id: 1003, name: "Aaron", age: 26 }, { id: 1004, name: "Casper", age: 26 }]; </script> </body> </html> 

參考

  1. HTML5 本地存儲——IndexedDB
  2. MDN
  3. indexedDB 標準
相關文章
相關標籤/搜索