客戶端持久化數據庫---indexedDB使用

閱讀目錄javascript

一:什麼是indexedDB數據庫?html

indexedDB是瀏覽器中的事務類型對象存儲數據庫。indexedDB適合大量的結構的數據存儲。java

適用場景:當數據量不是很大的時候,咱們能夠使用sessionStorage或LocalStorage來進行存儲,可是當數據量很是大的時候,咱們須要使用本地數據庫來存儲,所以這個時候 indexedDB 瀏覽器數據庫應運而生。數據庫

indexedDB 有以下特色:跨域

1)異步的;indexedDB打開數據庫或獲取數據的時候都是異步的,也就是說它不會堵塞瀏覽器操做。異步就是爲了防止大量數據的讀寫操做,防止網頁變慢或卡頓。數組

2)鍵值對存儲。indexedDB內部採用對象倉庫(object store) 來存放數據的,全部類型的數據均可以直接存儲。在對象倉庫中,
數據以 "鍵值對" 的形式保存,每個數據記錄都有對應的主鍵,主鍵是不可重複的。瀏覽器

3)支持事務型的。indexedDB執行的操做會按照事務來分組的,在一個事務中,要麼全部的操做都成功,要麼全部的操做都失敗。session

4)同源限制。indexedDB有同源限制,每個數據庫只能在自身域名下能訪問,不能跨域名訪問。app

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 下的數據以下所示:

能夠看到咱們全部的數據都被清空了。

相關文章
相關標籤/搜索