indexedDB transaction 事務

admin發表於2019-07-20

如果是後臺程式設計人員,那麼對資料庫事務一定非常熟悉,因為這是必須要掌握的知識。

indexedDB資料庫中同樣具有事務,目的與關係型資料庫是一樣的,確保資料庫操作的安全。

一.事務的必要性:

事務可以確保資料操作的安全性,如果資料操作中途出現意外,資料會回滾到最初的狀態。

不會出現修改部分資料的情況,這對於確保資料安全具有重要的意義,下面舉一個例子。

比如銀行A賬戶向B賬戶轉賬,在轉賬資料庫操作過程中突然出現意外,錢已經從A賬戶轉走,但是B還未收到。

這絕對是一個嚴重的問題,但是由於事務的存在,則會將兩個賬號回滾到最初的狀態,不存在資料部分修改。

二.程式碼例項:

首先給出一段程式碼例項,並對其進行一個簡單分析,以期對事務有一個直觀的感受。

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
let request = window.indexedDB.open("antzone", 1);
request.onupgradeneeded = (ev) => {
  let db = ev.target.result;
  if (!db.objectStoreNames.contains('students')) {
    let objectStore = db.createObjectStore('students',{keyPath:"id"});
    objectStore.createIndex("xingbie","sex",{ unique: false });
  }
}
 
request.onsuccess = (ev) => {
  let db = ev.target.result;
  let transaction = db.transaction(['students'], 'readwrite');
  let objectStore = transaction.objectStore('students');
  objectStore.add({
    id:1,
    name:"螞蟻部落",
    age:20,
    sex:"男"
  });
}
</script>
</head>
<body>
  <p>通過事務為資料新增一條資料</p>
</body>
</html>

上述程式碼執行效果截圖如下:

aid[3398]

上面程式碼將對應的資料寫入資料庫,程式碼分析如下:

(1).關於資料庫的建立與開啟本文不再詳細介紹,具體參閱相關閱讀。

(2).資料庫開啟成功後會觸發success,在事件處理函式中利用事務完成資料新增工作。

(3).通過IDBDatabase資料庫物件的transaction()方法建立一個事務,此方法接受兩個引數,第一個引數是陣列,陣列元素是此事務涉及到的物件倉庫,第二個引數規定事務的模式,上述程式碼設定事務是可讀寫的。

(4).然後再通過事務物件的objectStore()方法獲取對應的物件倉庫。

(5).最後利用物件倉庫的add()方法新增對應的資料。

三.事務模式:

對於資料庫操作主要如下幾種方式:

(1).讀取資料。

(2).讀寫資料。

(3).修改資料庫結構的schema。

事務具有三種模式:

(1).readonly:只讀模式,僅用於讀取資料。

(2).readwrite:讀寫模式,用於資料庫讀資料或者寫資料。

(3).verionchange:版本變更模式,用於資料庫讀寫資料或者修改資料庫結構的schema。

在前面的程式碼例項中演示了資料庫的"readwrite"讀寫模式,"read"模式很簡單也很容易理解,不再演示。

關於transaction()方法更多內容可以參閱IDBDatabase.transaction() 建立事務一章節。

可能很多朋友對於verionchange模式感覺比較陌生,好像從來都沒有見到過它的應用。

並非如此,對於資料庫結構的修改,比如索引的建立刪除或者物件倉庫的建立刪除等都會在此事務模式下進行。

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
let request = window.indexedDB.open("antzone", 1);
request.onupgradeneeded = (ev) => {
  let db = ev.target.result;
  if (!db.objectStoreNames.contains('students')) {
    let objectStore = db.createObjectStore('students',{keyPath:"id"});
    objectStore.createIndex("studentname","name",{ unique: false });
  }
}
</script>
</head>
<body>
  <p>建立一個資料庫,並新增物件倉庫</p>
</body>
</html>

上述程式碼建立一個資料庫,並新增物件倉庫,程式碼執行效果截圖如下:

aid[3399]

上述程式碼建立了一個資料庫,然後新增物件倉庫,並設定主鍵與索引,但是並未看到事務的應用。

當觸發upgradeneeded事件之時,會自動建立一個模式為"verionchange"的事務,注意不能人工建立。

通過下面程式碼例項做一下證明:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
let request = window.indexedDB.open("antzone", 2);
request.onupgradeneeded = (ev) => {
  let db = ev.target.result;
  if (!db.objectStoreNames.contains('students')) {
    let objectStore = db.createObjectStore('students',{keyPath:"id"});
    objectStore.createIndex("studentname","name",{ unique: false });
  }
  console.log(ev.target.transaction.mode)
}
</script>
</head>
<body>
  <p>建立一個資料庫,並新增物件倉庫</p>
</body>
</html>

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201907/20/142611jriorr44q457l9l7.jpg\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

注意要修改indexedDB.open()方法的第二個引數,以便觸發upgradeneeded事件。

四.注意事項:

(1)."readonly"事務可以同時作用於同一個物件倉庫或者索引。

(2)."readwrite"事務不能同時作用於同一個物件倉庫或者索引,只能夠按照順序操作。

(3)."verionchange"事務可以用於新增刪除或者更新資料,但更多的是用於建立物件倉庫和對物件倉庫的配置操作,此事務不能手動建立,而是在upgradeneeded事件觸發時自動建立,並且此事務具有排他性,當它在執行的時候,不能有其他事務同時執行。

程式碼例項如下:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
let request = window.indexedDB.open("antzone", 2);
request.onupgradeneeded = (ev) => {
  let db = ev.target.result;
  if (!db.objectStoreNames.contains('students')) {
    let objectStore = db.createObjectStore('students',{keyPath:"id"});
  }
  let trans = db.transaction(['students'], "readwrite");  
  let objectstore=  trans.objectStore("students");
  let addReq = objectstore.add({id:1,name:"螞蟻部落",age:5,address:"青島市南區"});
}
</script>
</head>
<body>
  <p>verionchange模式事務具有排他性</p>
</body>
</html>

程式碼執行效果截圖如下:

a:3:{s:3:\"pic\";s:43:\"portal/201907/20/142706yl8lk98cioi97ux9.jpg\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

上述程式碼可以修改如下:

[HTML] 純文字檢視 複製程式碼執行程式碼
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>螞蟻部落</title>
<script>
let request = window.indexedDB.open("antzone", 2);
request.onupgradeneeded = (ev) => {
  let db = ev.target.result;
  if (!db.objectStoreNames.contains('students')) {
    let objectStore = db.createObjectStore('students',{keyPath:"id"});
  }
  let trans = ev.target.transaction;
  let objectstore=  trans.objectStore("students");
  let addReq = objectstore.add({id:1,name:"螞蟻部落",age:5,address:"青島市南區"});
}
</script>
</head>
<body>
  <p>verionchange模式事務同樣具有讀寫功能</p>
</body>
</html>

程式碼執行效果截圖如下:

aid[3402]

上述程式碼並沒有建立新的事務,依然是使用upgradeneeded觸發時建立的事務。

相關文章