閱讀目錄
- 一:什么是indexedDB數據庫?
-
二:IndexedDB數據庫操作
一:什么是indexedDB數據庫?
indexedDB是瀏覽器中的事務類型對象存儲數據庫。indexedDB適合大量的結構的數據存儲。
適用場景:當數據量不是很大的時候,我們可以使用sessionStorage或LocalStorage來進行存儲,但是當數據量非常大的時候,我們需要使用本地數據庫來存儲,因此這個時候 indexedDB 瀏覽器數據庫應運而生。
indexedDB 有如下特點:
1)異步的;indexedDB打開數據庫或獲取數據的時候都是異步的,也就是說它不會堵塞瀏覽器操作。異步就是為了防止大量數據的讀寫操作,防止網頁變慢或卡頓。
2)鍵值對存儲。indexedDB內部采用對象倉庫(object store) 來存放數據的,所有類型的數據都可以直接存儲。在對象倉庫中,
數據以 "鍵值對" 的形式保存,每一個數據記錄都有對應的主鍵,主鍵是不可重復的。
3)支持事務型的。indexedDB執行的操作會按照事務來分組的,在一個事務中,要么所有的操作都成功,要么所有的操作都失敗。
4)同源限制。indexedDB有同源限制,每一個數據庫只能在自身域名下能訪問,不能跨域名訪問。
5)存儲空間大。存儲空間可以達到幾百兆甚至更多。
6)支持二進制存儲。它不僅可以存儲字符串,而且還可以存儲二進制數據(ArrayBuffer對象或Blob對象)。
2.1 打開或創建數據庫
使用indexedDB的第一步是打開我們的數據庫,使用 indexedDB.open()方法,如下所示:
<!DOCTYPE html> <html> <head> <title>indexedDB數據庫使用</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0"> </head> <body> <script type="text/javascript"> var request = window.indexedDB.open('my-database', 1); console.log(request); </script> </body> </html>
打印 如上的 信息,如下所示:
該方法接收2個參數,第一個參數是字符串,表示數據庫的名字。如果指定的數據庫不存在的話,就會新建該數據庫。第二個參數是一個整數,它表示的是數據庫的版本。如果省略第二個參數的話,如果是新建數據庫的話,默認為1. 如果是打開已有的數據庫的話,默認就為當前的版本。
數據庫被創建完成后,我們可以打開我們的控制台 -> application -> indexedDB 下 就有 我們剛剛的 my-database 數據庫了,如下所示:
從上面打印的信息我們可以看到,創建一個數據庫完成后,該實列有 onerror, onsuccess, onupgradeneeded 監聽函數。及 result 屬性值。
indexedDB.open() 方法返回的是一個IDBRequest對象,代表一個請求連接數據庫的請求對象。該對象通過三種事件:onerror、onsuccess、onupgradeneeded 處理打開數據庫的操作結果的。我們可以通過監聽請求對象的 onsuccess 和 onerror 事件來定義連接成功或失敗需要執行的方法。如下代碼:
var request = window.indexedDB.open('my-database'); var db; request.onerror = function() { console.log('數據庫打開報錯'); } request.onsuccess = function(event) { console.log(event.target); db = request.result; console.log('數據庫打開成功'); } request.onupgradeneeded = function(event) { console.log('數據庫升級事件'); console.log(event.target); db = event.target.result; }
如上代碼執行的結果如下:
如上我們可以看到,會執行我們的 onsuccess的方法,但是 onupgradeneeded 是不會執行的,該監聽函數只監聽當當前的版本號升級的時候才會被觸發,也就是說,數據庫的版本號更改為大於當前的數據庫的版本才會被執行。
注意:從上面我們也可以看到 event.target === request 實列對象.
當我們現在把數據庫的版本號升級到2的時候,之前的版本號是1,現在數據庫的版本升級了,就會觸發 onupgradeneeded 事件,如下代碼所示:
var request = window.indexedDB.open('my-database', 2); var db; request.onupgradeneeded = function(event) { console.log('數據庫升級事件'); console.log(event.target); db = event.target.result; }
實現效果如下所示:
2.2 創建對象倉庫(或叫創建表)
如上我們的indexedDB數據庫新建完成后,我們現在要做的事情就行新建表格了。不過在indexedDB中沒有數據庫表,而叫對象倉庫,不過它的作用就相當於一個數據庫表。它使用的 createObjectStore 來創建的,如下代碼演示:
var request = window.indexedDB.open('my-database', 3); var db; request.onupgradeneeded = function(event) { db = event.target.result; var store; if (!db.objectStoreNames.contains('Users')) { store = db.createObjectStore('Users', {keyPath: 'id', autoIncrement: true }); } console.log('創建對象倉庫成功'); console.log(store); }
如上代碼,db.createObjectStore 方法接收2個參數,第一個為對象的倉庫名(也可以理解我們之前的數據庫表名),第二個參數為可選參數,值為一個js對象,該對象中的 keyPath屬性為主鍵,autoIncrement 屬性為 true,表示主鍵值自增。
db.objectStoreNames.contains('Users') 的含義:是否包含該對象倉庫名(或叫表名)。如果不包含就創建一個。
2.3 創建索引
在indexedDB中,我們使用 createIndex 來創建它的索引。通過數據對象的某個屬性來創建索引,在數據庫中進行檢索數據的時候,我們只能通過被設置為索引的屬性來進行檢索的。
如下代碼:
var request = window.indexedDB.open('my-database', 4); var db; request.onupgradeneeded = function(event) { db = event.target.result; var store; if (!db.objectStoreNames.contains('newUsers')) { store = db.createObjectStore('newUsers', {keyPath: 'id', autoIncrement: true }); } console.log(store); // 創建索引 store.createIndex('userIndex', 'userName', { unique: false }); store.createIndex('userEmail', 'email', { unique: true }); console.log('創建索引成功'); }
如上代碼:store.createIndex 方法接收三個參數,第一個為索引名,第二個為數據對象的屬性,第三個參數是可選參數,值為一個js對象,該對象中的 unique 屬性值為true,代表該索引值是唯一的,不可以相同的。如果為false的話,則可以相同。
索引創建完成后,我們需要事務操作了。
2.4 新增數據
在indexedDB中,我們能夠使用事務來進行數據庫的操作,事務有三個模式。
1. readOnly: 只讀
2. readwrite: 可讀可寫
3. versionchange: 數據庫版本變化
我們創建一個事務時,需要選擇一種模式,如果不指定的話,則默認為只讀模式。比如代碼如下:
var transaction = db.transaction(['customers'], 'readwrite');
創建事務我們使用 db.transaction方法。該方法接收2個參數,第一個參數是字符串或數組,字符串是一個對象的倉庫名。數組則是由對象倉庫名組成的數組。第二個參數是事務模式。比如上面的模式是只讀,或 可讀可寫。
新增數據指的是向對象倉庫寫入數據記錄,這需要通過事務完成。該方法接收一個參數,保存到對象倉庫中的對象。
如下代碼所示:
var request = window.indexedDB.open('my-database', 4); var db; request.onupgradeneeded = function(event) { db = event.target.result; var store; if (!db.objectStoreNames.contains('newUsers')) { store = db.createObjectStore('newUsers', {keyPath: 'id', autoIncrement: true }); } console.log(store); // 創建索引 store.createIndex('userIndex', 'userName', { unique: false }); store.createIndex('userEmail', 'email', { unique: true }); console.log('創建索引成功'); } request.onsuccess = function(event) { db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); objStore.add({name: 'a', age: 10}); objStore.add({name: 'b', age: 20}); }
如上代碼,我們使用 var transaction = db.transaction(['newUsers'], 'readwrite'); 代碼來創建一個事務,第一個參數 'newUsers' 是對象倉庫名,是我們之前在 onupgradeneeded 函數里面創建倉庫的。事務新建以后,我們使用 transaction.objectStore('newUsers') 這個方法,拿到 IDBObjectStore 對象,再通過表格對象的add()方法,向表格寫入一條記錄。如下所示:
2.5 讀取數據
讀取數據也是通過事務完成的。如下代碼:
var request = window.indexedDB.open('my-database', 4); var db; request.onsuccess = function(event) { db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); // 讀取數據 var req = objStore.get(1); req.onsuccess = function(e) { if (req.result) { console.log('已經查詢到數據為:'); console.log(req.result); } else { console.log('未查詢到數據'); } } }
如上面代碼中,objStore.get()方法用於讀取數據,參數是主鍵的值。比如我們來查看下我們的主鍵key在我們的Application下有如下key值;
如上我們獲取的key = 1;因此打印的效果如下所示:
2.6 遍歷數據
如果我們需要遍歷整個存儲空間的數據時,我們就需要使用流標,流標通過對象倉庫的 openCursor方法創建打開,該方法可以傳遞2個參數,第一個參數是 IDBKeyRange對象,第二個參數表示流標的讀取方向。
我們來看下第一個參數的使用方法如下所示:
/* boundRange 表示主鍵從1到10(包含1和10)的集合 如果第三個參數是true的話,則表示不包含最小的鍵值1。 如果第四個參數是true的話,則表示不包含最大鍵值10,默認都為false */ var boundRange = IDBKeyRange.bound(1, 10, false, false); // onlyRange 表示由一個主鍵值的集合。only里面的參數值為主鍵值,整數類型。 var onlyRange = IDBKeyRange.only(1); /* lowerRange 表示大於等於1的主鍵值的集合。 第二個參數可選,為true表示不包含最小主鍵1,默認為false */ var lowerRange = IDBKeyRange.lowerBound(1, false); /* upperRange 表示小於等於10的主鍵值的集合。 第二個參數可選,為true則表示不包含最大主鍵10,false則包含,默認為false */ var upperRange = IDBKeyRange.upperBound(10, false);
openCursor方法 的第二個參數表示流標的讀取方向,主要有以下幾種:
next: 流標中的數據按主鍵值升序排序,主鍵值相等的數據都被讀取到。
nextunique: 流標中的數據按主鍵值升序排序,主鍵值相等只讀取第一條數據。
prev: 流標中的數據按主鍵值降序排序,主鍵值相等的數據都被讀取。
prevunique: 流標中的數據按主鍵值降序排序,主鍵值相等只讀取第一條數據。
如果不使用參數的話,則是查詢所有的記錄,使用方法代碼如下所示:
var request = window.indexedDB.open('my-database', 4); var db; var datas = []; request.onsuccess = function(event) { db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); // 使用流標 openCursor objStore.openCursor().onsuccess = function(e) { var cursor = e.target.result; if (cursor) { console.log(cursor); datas.push(cursor); cursor.continue(); } else { console.log('沒有數據了'); console.log(datas); } } }
打印 cursor 信息如下所示:
下面我們使用 openCursor中兩個參數來看下demo,如下所示代碼:
var request = window.indexedDB.open('my-database', 6); var db; var datas = []; request.onsuccess = function(event) { console.log(IDBKeyRange) console.log(111); db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); var range = IDBKeyRange.bound(2, 10); // 使用流標 openCursor console.log(222); objStore.openCursor(range, 'next').onsuccess = function(e) { var cursor = e.target.result; if (cursor) { console.log(cursor); datas.push(cursor); cursor.continue(); } else { console.log('沒有數據了'); console.log(datas); } } }
如上 IDBKeyRange.bound(2, 10)方法的含義是:表示主鍵從2到10的集合. objStore.openCursor(range, 'next') 的含義是:流標中的數據按主鍵值升序排序,主鍵值相等的數據都被讀取到。我們首先來看下我們的 my-database 數據庫中 newUsers表中的數據如下:
可以看到如上面我們的id就是我們的主鍵。然后我們如上運行結果如下所示:
更多的相關IDBKeyRange的API請看官網
2.7 更新數據
更新數據我們需要使用 IDBObject.put() 方法。該方法也是接收一個參數,為需要保存到對象倉庫中的對象。
var request = window.indexedDB.open('my-database', 4); var db; request.onsuccess = function(event) { console.log(IDBKeyRange) console.log(111); db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); var newValue = { 'name': 'kongzhi', 'age': '30', 'id': 1 }; // 更新數據 var req1 = objStore.put(newValue); // 獲取主鍵為1的數據 var req2 = objStore.get(1); // 加載主鍵為1的數據 req2.onsuccess = function(e) { var cursor = e.target.result; if (cursor) { console.log(cursor); } else { console.log('沒有數據了'); } } }
如上代碼,我們使用 objStore.put(newValue); 這個方法去更新主鍵為1的數據,然后使用 objStore.get(1) 方法來獲取主鍵為1的數據,最后監聽 success 方法函數,成功后獲取數據,打印信息如下圖所示:
然后我們繼續來看下 我們的控制台 -> application 下的 newUsers中的數據被更新成如下:
2.8 刪除數據
我們使用 IDBObjectStore.delete() 方法用於刪除記錄。代碼如下所示:
var request = window.indexedDB.open('my-database', 4); var db; request.onsuccess = function(event) { console.log(IDBKeyRange) console.log(111); db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); // 刪除主鍵為1的數據 var res = objStore.delete(1); // 加載主鍵為1的數據 res.onsuccess = function(e) { console.log('刪除成功了'); } }
如上代碼,我們使用 objStore.delete(1) 方法刪除主鍵為1的代碼,然后在控制台中我們看到會打印 刪除成功的 文案,然后我們到 我們的 application 再看看如下所示:
如上我們可以看到,我們的主鍵為1的記錄沒有了。
2.9 使用索引
索引的作用就是可以讓我們搜索任意字段,我們可以根據索引來搜索任何一條記錄,有索引使我們搜索的速度更快,就好比我們的一本書目錄一樣,它也有
對應的索引含義,我們可以根據該索引能快速查找到我們這一本書上的某一個知識點在第幾頁。在這里我們默認是按照主鍵來搜索。
如上創建索引那塊的地方,我們可以看到使用如下語法創建索引:
store.createIndex('userIndex', 'userName', { unique: false });
我們首先來看下我們 索引userIndex 有如下值:如下所示:
現在我們使用普通的流標的方法來獲取索引,代碼如下所示:
var request = window.indexedDB.open('my-database', 6); var db; var datas = []; request.onupgradeneeded = function(event) { db = event.target.result; var store; if (!db.objectStoreNames.contains('newUsers2')) { store = db.createObjectStore('newUsers2', {keyPath: 'id', autoIncrement: true }); console.log(store); // 創建索引 store.createIndex('userIndex', 'userName', { unique: false }); console.log('創建索引成功1111'); } } request.onsuccess = function(event) { db = event.target.result; var transaction = db.transaction(['newUsers2'], 'readwrite'); var objStore = transaction.objectStore('newUsers2'); var req = objStore.index('userIndex').openCursor(); req.onsuccess = function(e) { var res = e.target.result; if (res) { console.log(res); datas.push(res); res.continue(); } else { console.log('沒有數據了'); console.log(datas); } } }
然后我們在onsuccess函數內部使用 datas數組,往數組里面添加一條數據,然后使用 res.continue(); 繼續調用,因此多條數據都會被添加到 datas 數組里面去了,如下所示:
2.10 清空所有的數據 clear() 方法
我們現在來清空下 newUsers 倉庫里面的數據,我們沒有調用 clear() 方法清空之前,我們來看下 newUsers 表中有哪些數據,如下所示:
現在我們看如下代碼,就可以清空 newUsers 倉庫中所有的數據了,如下代碼所示:
var request = window.indexedDB.open('my-database', 6); var db; var datas = []; request.onsuccess = function(event) { console.log(IDBKeyRange) console.log(111); db = event.target.result; var transaction = db.transaction(['newUsers'], 'readwrite'); var objStore = transaction.objectStore('newUsers'); objStore.clear(); objStore.onsuccess = function(e) { var res = e.target.result; console.log(res); } }
然后我們繼續來查看下我們的 Application 下的數據如下所示:
可以看到我們所有的數據都被清空了。