1、indexedDB是什么?
-
indexedDB是一個非關系型數據庫
-
它不需要我們去寫一些特定的SQL語句來對數據庫進行操作
-
它是NoSQL的,數據形式使用的json
2、indexedDB出現的意義?
-
前端存儲,已經有了LocalStorage 和 Cookies ,但是它們都是比較簡單的技術。
-
而indexedDB提供了 類似數據庫風格的數據儲存 和 使用方式
-
Cookies只能是字符串,儲存空間有限,每次HTTP接受和發送都會傳遞Cookies數據,它會占用額外的流量
-
LocalStorage是用key-value 鍵值模式儲存數據,想讓localstorage存儲對象,你需要借助JSON.stringify() 能將對象變成字符串形式,再用JSON.parse() 將字符串還原成對象,當存儲的數據龐大時,這就不是最佳的方案了,localstorage就是專門為小數量數據設計的,它的api設計為同步的
-
indexedDB很適合存儲大量數據,它的API是異步調用的,indexedDB使用索引存儲數據,各種數據庫操作放在事務中執行,indexedDB支持簡單的數據類型,它比localstorage強大,API也相對復雜,對於簡單的數據,還是使用localstorage。
-
indexedDB能提供更為復雜的查詢數據的方式
3、indexedDB的特性
-
對象倉庫(objectStore)
-
indexedDB沒有表的概念,而是使用objectStore。
-
一個數據庫中可以包含多個objectStore
-
objectStore是一個靈活的數據結構,可以存放多種類型數據,也就是說一個objectStore相當於一張表,里面儲存的每條數據和一個鍵相關。
-
我們可以使用每條記錄中的某個字段作為鍵值(keyPath),也可以使用自動生成的遞增數字作為鍵值(keyGenerator),也可以不指定。
-
選擇鍵的類型不同,objectStore可以存儲的數據結構也有差異
-
-
事務性
-
在indexedDB中,每一個對數據庫操作是在一個事務的上下文中執行的。
-
事務范圍一次影響一個或多個objectstores。
-
你通過傳入一個objectstores名字的數組到創建事務 范圍的函數來定義
-
比如: db.transaction( storeName, ' readwrite' ),創建事務的第二個參數是事務模式,當請求一個事務時,必須決定是按照只讀還是讀寫模式模式請求訪問
-
-
-
基於請求
-
對indexedDB數據庫的每次操作,描述為通過一個請求打開數據庫,訪問一個object store,再繼續。
-
indexedDB API天生是基於請求的,這也是API異步本性指示,對於你在數據庫執行的每次操作,你必須首先為這個操作創建一個請求,當請求完成,你可以響應由請求結果產生的事件和錯誤
-
-
異步
-
在indexedDB 大部分操作並不是我們常用的調用方法,返回結果的模式,而是請求 ----> 響應的模式
-
所謂異步API是指並不是這條指令執行完畢,我們就可以使用 request.result 來獲取 indexedDB 對象了。
-
類似於 我們使用ajax一樣,語句執行完並不代表已經獲取到了對象,所以我們一般在其回調函數中處理。
-
4、玩 indexedDB 的基本步驟
-
打開數據庫並且開始一個事務
-
創建一個 object store
-
構建一個請求執行一些數據庫操作,比如新增或者提取數據等
-
通過監聽正確類型的DOM事件可以等待操作完成
-
在操作結果上進行一些操作(可以在 request 對象中找到)
代碼案例:
1、打開數據庫,需要當前瀏覽器支持indexedDB
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB; if( !indexedDB ){ alert('當前不支持 indexedDB 數據庫'); throw Error('當前不支持 indexed 數據庫'); }
2、創建數據庫
function createDB(dbName, version) { // 參數為:數據庫名和版本號 // 數據庫存在則打開,否則創建 let request = indexedDB.open(dbName, version); /** * request 並不會返回一個DB對象的句柄,我們得到的是一個IDBOpenDBRequest對象 * 而我們期望得到的DB對象在其result屬性中 * 除了 result,IDBOpenDBRequest 接口定義了幾個重要屬性 * onerror:請求失敗的回調函數句柄 * onsuccess:請求成功的回調函數句柄 * onupgradeneeded:請求數據庫版本變化句柄 * 第一次打開數據庫,會先觸發 onupgradeneeded 事件,然后觸發success事件。 */ console.log(request); // 請求數據庫失敗的回調函數 request.onerror = function(err) { console.log(JSON.stringify(err)); console.log('打開數據庫失敗,錯誤信息為:' + err.target.message); } // 請求數據庫成功的回調函數 request.onsuccess = function(success) { console.log(JSON.stringify(success)); console.log('打開數據庫成功:' + success.target.result); /** * 獲取數據庫實例對象, * db.createObjectStore('table6',{keyPath:'stuId',autoIncrement:true}); * var len = db.objectStoreNames.length; --> 對象儲存空間名的個數 * var name = db.objectStoreNames[1]; --> 對象存儲空間名 * transaction = db.transaction(['table'],'readwrite'); --> 事務操作的對象存儲空間名,事務模式:'readwrite'可讀寫模式 * * // 向info儲存空間加入一個info對象,獲得request對象用於處理用戶對數據庫的操作請求 * // 同樣擁有 onerror 、onupgradeneeded 、onsuccess 事件 * objectStore = transaction.objectStore('table'); */ let db = success.target.result; } // 數據庫版本更新 request.inuparadeneeded = function(event) { console.log(JSON.stringify(event)); console.log('數據庫版本有變化...'); let db = event.target.result; // 判斷對象儲存空間名稱是否存在 if (!db.objectStoreNames.contains('table')) { //創建信息對象存儲空間;指定keyPath選項為Id(即主鍵為Id) let objectStore = db.createObjectStore('table', { keyPath: 'stuId', autoIncrement: true }); /* *db.createObjectStore("table1", {keyPath: "userId",autoIncrement: true}); *db.createObjectStore("table2", {keyPath: "userId",autoIncrement: true}); *db.createObjectStore("table3", {keyPath: "userId",autoIncrement: true}); *db.createObjectStore("table4", {keyPath: "userId",autoIncrement: true}); *當然了。你可以一次性的在這里建立多個對象空間 或者每次改變 version和對象空間的名字。之前創建的會存在。 * 為什么在onupgradeneeded中創建呢? * 原因:當dbName和 version 這兩個參數中的任何一個發生變化。都會執行重新創建一遍對象空間, * 注意:當dbName,保持不變,version 只能逐漸增加,假如你這次 version = 3.那么下次 version = 2.就會報錯 打開數據庫失敗: * version!=0; * */ // 創建索引 // 索引名,創建索引的列,索引選項(索引屬性值是否唯一:true or false) // 注意: 創建索引 要在創建對象空間的時候 // unique:true 實際效果:這個索引的內容是唯一的,不能重復,無法創建兩個(索引屬性值)相同的內容 objectStore.createIndex('studentIndex', 'stuId', { unique: true }); } } }
3、刪除數據庫 or 關閉數據庫
// 關閉與刪除數據庫 function deleteDB(dbName) { try { // 刪除數據庫使用 indexedDB對象的deleteDatabase方法 let request = indexedDB.deleteDatabase(dbName); request.onerror = function() { console.log('刪除[' + dbName + ']數據庫失敗!!!!'); } request.onsuccess = function() { console.log('刪除[' + dbName + ']數據庫成功!!!!'); } } catch (e) { console.log('刪除[' + dbName + ']數據庫出現錯誤,' + e.getMessage); } } // 關閉數據庫 function colseDB(dbName){ dbName.close(); }
4、新增數據
// 新增數據 // 數據庫名稱,對象倉庫(表名),傳入的參數 function insert(dbName, objectStoreName, argument) { // 打開數據庫 let request = indexedDB.open(dbName); // 請求數據庫成功的回調函數 request.onsuccess = function(success) { // 獲取數據庫實例對象 let db = success.target.result; // 對某個表 進行事務操作的事務權限控制 let transaction = db.transaction(objectStoreName, 'readwrite'); // 對表進行操作 let objectStore = transaction.objectStore(objectStoreName); // 使用add方法,此方法是異步的 // 有success,error事件 //objectStore.add(argument); // 使用定義add方法 let add = objectStore.add(argument); let msg = JSON.stringify(argument); // 添加成功的回調函數 add.onsuccess = function(e) { console.log(e); console.log('向表[' + objectStoreName + ']新增一條數據為[' + msg + ']成功!!'); } add.error = function(e) { console.log('向表[' + objectStoreName + ']新增一條數據為[' + msg + ']失敗!!'); } } } var stu1 = { name: '歐可樂', age: 19, sex: '男' }; insert('studentDB','student',stu1);
5、查詢數據
// 查詢數據 // 數據庫名,對象倉庫(表名),查詢參數(鍵名對應的值) function getData(dbName, objectStoreName, selectArgument){ // 打開數據庫 let request = indexedDB.open(dbName); // 請求打開數據庫的回調函數 request.onsuccess = function(success){ let db = success.target.result; let transaction = db.transaction([objectStoreName],'readwrite'); let objectStore = transaction.objectStore(objectStoreName); let getResult = objectStore.get(selectArgument); getResult.onsuccess = function(e){ console.log( e.target.result); } } } getData('studentDB','student',1);
6、更新數據
// 更新數據 // 數據庫名,表名,要更新數據的標志(id),新的數據 function update(dbName, objectStoreName, id, newsData) { // 打開數據庫 let request = indexedDB.open(dbName); // 請求打開數據庫的回調函數 request.onsuccess = function(success) { // 獲取到數據庫的表 let db = success.target.result; // 對表操作進行事務權限控制 let transaction = db.transaction(objectStoreName, 'readwrite'); // 對表進行操作 let objectStore = transaction.objectStore(objectStoreName); // 根據鍵值 獲取某個實例中的某條數據 let getResult = objectStore.get(id); // 實例成功的回調函數 getResult.onsuccess = function(e) { // 源數據 let msg = e.target.result; let old = JSON.stringify(msg); // 重新賦值 msg.name = newsData.name; msg.age = newsData.age; msg.sex = newsData.sex; objectStore.put(msg); console.log('更新主鍵為 stuId:' + msg.stuId + '的數據,原數據:[' + old + '],新數據為:[' + JSON.stringify(e.target.result) + '],更新成功!!!'); } // 實例失敗的回調函數 getResult.onerror = function(e) { console.log('數據更新失敗!!'); } } } let stu2 = { name: '小可樂', age: 18, sex: '男' } update('studentDB', 'student', 1, stu2);
7、刪除數據
// 刪除數據 // 數據庫名,表名,主鍵 function deleteData(dbName, tableName, id){ // 打開數據庫 let request = indexedDB.open(dbName); // 請求打開數據庫成功的回調函數 request.onsuccess = function(success){ // 獲取實例 let db = success.target.result; // 事務權限控制 let transaction = db.transaction(tableName, 'readwrite'); // 進行操作 let objectStore = transaction.objectStore(tableName); // 進行刪除 let deleteMsg = objectStore.delete(id); deleteMsg.onsuccess = function(e){ console.log('成功刪除主鍵stuId為:' + id+',的數據,狀態為:'+e.isTrusted); } } } deleteData('studentDB','student',1);
8、清除表數據
// 清空表數據 // 數據庫名稱,表名 function clearData(dbName, tableName) { // 請求打開數據庫 let request = indexedDB.open(dbName); // 請求成功的回調函數 request.onsuccess = function(e) { // 獲取實例 let db = e.target.result; // 表名事務權限控制 let transaction = db.transaction(tableName, 'readwrite'); // 進行操作 let objectStore = transaction.objectStore(tableName); // 清除數據 let clearResult = objectStore.clear(); // 清除成功的回調函數 clearResult.onsuccess = function(e) { console.log('表名[' + tableName + ']數據清除成功,狀態為:' + e.isTrusted ); } } } clearData('studentDB', 'student');
9、使用索引查詢
// 利用索引查詢 // 數據庫,表名,索引名, 查詢的值 function searchIndex(dbName, tableName, indexName, indexValue) { // 請求打開數據 let request = indexedDB.open(dbName); // 請求打開數據庫成功的回調函數 request.onsuccess = function(e) { // 獲取到實例 let db = e.target.result; // 賦予事務權限 let transaction = db.transaction(tableName, 'readwrite'); // 基於權限進行操作 let objectStore = transaction.objectStore(tableName); // 索引 let index = objectStore.index(indexName); // 獲取結果 let result = index.get(indexValue); // 結果獲取成功的回調函數 result.onsuccess = function(e) { console.log('索引名:' + indexName + ',索引值:' + indexValue + ',查詢的結果:[' + JSON.stringify( e.target.result ) + ']'); } } } searchIndex('studentDB','student','studentIndex',2);
10、使用游標讀取全部的數據
// 使用 游標 // 數據庫名稱,表名 function readAll(dbName, tableName) { // 請求打開數據庫 let request = indexedDB.open(dbName); // 請求成功的回調函數 request.onsuccess = function(e) { // db = e.target.result // 獲取實例 // transaction = db.transaction(tableName,'readwrite'); // 權限控制 // objectStore = transaction.objectStore(tableName); // 進行操作對象 let objectStore = e.target.result.transaction(tableName, 'readwrite').objectStore(tableName); // 打開游標 let cursor = objectStore.openCursor(); // 儲存值 let arr = []; // 成功打開游標的回調函數 cursor.onsuccess = function(e) { let result = e.target.result; if (result) { // 將數據一條一條保存到arr中 arr.push(result.value); result.continue(); } else { if (!arr) { console.log('沒有數據....'); } else { console.log('[' + tableName + ']表中的數據為:' + JSON.stringify(arr)); } } } } } readAll('studentDB', 'student');