引用文檔:
HTML5本地存儲——IndexedDB(一:基本使用)
HTML5本地存儲——IndexedDB(二:索引)
IndexedDB API
JavaScript高級程序設(shè)計(第三版)
IndexedDB簡介:
IndexedDB是在瀏覽器中保存結(jié)構(gòu)化數(shù)據(jù)的一種數(shù)據(jù)庫,IndexedDB的思想是創(chuàng)建一套API,方便保存和讀取JavaScript對象,同時支持查詢和搜索。IndexedDB的最大特色是使用對象保存數(shù)據(jù)。一個IndexedDB數(shù)據(jù)庫,就是一組位于相同命名空間下的對象的集合。
IndexedDB打開數(shù)據(jù)庫:
-
open
IndexedDB是一個作為API宿主的全局對象,由于IndexedDB設(shè)計的操作為異步進行,所以大多數(shù)的操作為請求操作,打開數(shù)據(jù)庫即向數(shù)據(jù)庫發(fā)送open請求,如下代碼所示,發(fā)送請求后,如果數(shù)據(jù)庫存在,就打開該數(shù)據(jù)庫,如果數(shù)據(jù)庫不存在,就創(chuàng)建并打開該數(shù)據(jù)庫,打開該數(shù)據(jù)庫成功后會返回一個IDBOpenDBRequest對象,這個對象上可以添加一系列的處理程序,如代碼中的onerror事件和onsuccess事件,在onsuccess中可以得到IDBDatabase對象。
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var request,database;
request = indexedDB.open('test');
request.onerror = function(e){
console.log(e.target.errorCode);
};
request.onsuccess = function(e){
database = e.target.result;
console.log('創(chuàng)建或打開數(shù)據(jù)庫成功') ;
}
以上代碼在控制臺中得到結(jié)果如下圖所示:

-
version
默認情況下,IndexedDB是沒有版本號的,最好一開始為數(shù)據(jù)庫指定一個版本號,我們可以在創(chuàng)建或者打開數(shù)據(jù)庫時為其指定版本號,在上述代碼中將open函數(shù)傳入的參數(shù)更改為request = indexedDB.open('test',1);這樣就為當前數(shù)據(jù)庫設(shè)定了版本號,通過設(shè)置版本號可以知道想使用的數(shù)據(jù)庫是否設(shè)置了合適的對象存儲空間,在整個Web應(yīng)用中,隨著數(shù)據(jù)庫的更新和修改,可能會產(chǎn)生很多個不同的版本號(ps:關(guān)于版本號的用途也沒有摸索特別清楚,可以確定的是每次增加對象存儲空間都是要修改版本號的。)
IndexedDB對象存儲空間:
在建立或者打開數(shù)據(jù)庫后,我們一般的操作是建立表,向表中插入數(shù)據(jù),在IndexedDB中,用對象存儲空間ObjectStore來代替表的概念,存儲空間中的對象就相當于表中插入的數(shù)據(jù)。在上一步打開數(shù)據(jù)庫的onsuccess中我們可以獲得到IDBDatabase對象,創(chuàng)建存儲空間就是在通過該對象調(diào)用createObjectStore函數(shù)。
var data=[{
id:1007,
name:"Byron",
age:24
},{
id:1008,
name:"Frank",
age:30
},{
id:1009,
name:"Aaron",
age:26
}];
var store = database.createObjectStore("students",{keyPath:"id"});
//var store = database.createObjectStore("students",{autoIncrement:true});
for(var i = 0 ; i < data.length;i++){
request = store.add(data[i]);
request.onerror = function(){
console.error('數(shù)據(jù)庫中已有該數(shù)據(jù)')
};
request.onsuccess = function(){
console.log('數(shù)據(jù)已存入數(shù)據(jù)庫')
};
}
上述代碼中createObjectStore第一個參數(shù)為存儲對象空間的名字,第二個參數(shù)為存儲空間的鍵,既數(shù)據(jù)庫表中的主鍵,我們進行查找或者刪除某個對象都要通過這個鍵來查找,如果不設(shè)置存儲空間的鍵,可以如代碼注釋行一樣,設(shè)置自增類型。
API文檔中對于該參數(shù)說明如下:

在瀏覽器中顯示如下:

- 錯誤說明
在創(chuàng)建存儲對象空間可能報如下錯誤:
Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction.報該錯誤的原因是:第一次open的success事件處于version_change事務(wù)中 這個時候不能createObjectStore,createObjectStore操作要在onupgradeneeded的事件中執(zhí)行。
為對象存儲空間添加數(shù)據(jù):
創(chuàng)建存儲空間之后,可以用add()或者put()方法為其添加數(shù)據(jù),這兩個方法都接收所要保存的對象,區(qū)別之處在于,使用add()方法,遇到鍵值相同的對象會返回錯誤,而put()則不會報錯,會重寫原有對象。如下代碼使用add()方法進行數(shù)據(jù)添加,代碼中包括打開數(shù)據(jù)庫及創(chuàng)建存儲對象空間。可在控制臺中直接運行。
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var request,database;
var data=[{
id:1007,
name:"Byron",
age:24
},{
id:1008,
name:"Frank",
age:30
},{
id:1009,
name:"Aaron",
age:26
}];
request = indexedDB.open('test',1);
request.onerror = function(){
console.log('error');
};
request.onsuccess = function(e){
database = e.target.result;
console.log('創(chuàng)建或打開數(shù)據(jù)庫成功') ;
};
request.onupgradeneeded=function(e){
database = e.target.result;
if(!database.objectStoreNames.contains("students")){
var store = database.createObjectStore("students",{autoIncrement:true});
for(var i = 0 ; i < data.length;i++){
request = store.add(data[i]);
request.onerror = function(){
console.error('數(shù)據(jù)庫中已有該數(shù)據(jù)')
};
request.onsuccess = function(){
console.log('數(shù)據(jù)已存入數(shù)據(jù)庫')
};
}
}
}
事務(wù)
創(chuàng)建對象存儲空間之后,數(shù)據(jù)庫中的增刪改查都是通過事務(wù)transaction來完成的,在數(shù)據(jù)庫對象上調(diào)用transaction()方法可以創(chuàng)建事務(wù)。
var transaction= database.transaction("students",'readwrite');
transaction.objectStore("students")
如上代碼保證只加載students存儲空間的數(shù)據(jù),然后通過事務(wù)訪問該空間,對該空間中的數(shù)據(jù)進行操作,transaction()中傳入的第二個參數(shù)為對該空間操作的方式,默認為readonly只讀操作,代碼中傳入的是readwrite讀寫操作。其它可訪問MDN APIIDBTransaction
完整代碼:
該demo可在控制臺中執(zhí)行函數(shù),由于IndexedDB API的異步進行,如果所有函數(shù)同時執(zhí)行,打印出來的信息會不按說明排列,建議想測試哪個功能在控制臺中執(zhí)行即可。默認功能為建立打開數(shù)據(jù)庫、創(chuàng)建存儲空間添加數(shù)據(jù)。
demo默認執(zhí)行圖示


demo在控制臺中完整執(zhí)行圖示

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="author" content="sina_mobile">
<meta name="format-detection" content="telephone=no" />
<title></title>
</head>
<body>
<script>
var myDB={
name:'univisity',
version:1,
db:null,
ojstore:{
name:'students',//存儲空間表的名字
keypath:'id'//主鍵
}
};
var INDEXDB = {
indexedDB:window.indexedDB||window.webkitindexedDB,
IDBKeyRange:window.IDBKeyRange || window.webkitIDBKeyRange,//鍵范圍
openDB:function(dbname,dbversion,callback){
//建立或打開數(shù)據(jù)庫,建立對象存儲空間(ObjectStore)
var self = this;
var version = dbversion || 1;
var request = self.indexedDB.open(dbname,version);
request.onerror = function(e){
console.log(e.currentTarget.error.message);
};
request.onsuccess = function(e){
myDB.db = e.target.result;
console.log('成功建立并打開數(shù)據(jù)庫:'+myDB.name+' version'+dbversion);
};
request.onupgradeneeded=function(e){
var db=e.target.result,transaction= e.target.transaction,store;
if(!db.objectStoreNames.contains(myDB.ojstore.name)){
//沒有該對象空間時創(chuàng)建該對象空間
store = db.createObjectStore(myDB.ojstore.name,{keyPath:myDB.ojstore.keypath});
console.log('成功建立對象存儲空間:'+myDB.ojstore.name);
}
}
},
deletedb:function(dbname){
//刪除數(shù)據(jù)庫
var self = this;
self.indexedDB.deleteDatabase(dbname);
console.log(dbname+'數(shù)據(jù)庫已刪除')
},
closeDB:function(db){
//關(guān)閉數(shù)據(jù)庫
db.close();
console.log('數(shù)據(jù)庫已關(guān)閉')
},
addData:function(db,storename,data){
//添加數(shù)據(jù),重復(fù)添加會報錯
var store = store = db.transaction(storename,'readwrite').objectStore(storename),request;
for(var i = 0 ; i < data.length;i++){
request = store.add(data[i]);
request.onerror = function(){
console.error('add添加數(shù)據(jù)庫中已有該數(shù)據(jù)')
};
request.onsuccess = function(){
console.log('add添加數(shù)據(jù)已存入數(shù)據(jù)庫')
};
}
},
putData:function(db,storename,data){
//添加數(shù)據(jù),重復(fù)添加會更新原有數(shù)據(jù)
var store = store = db.transaction(storename,'readwrite').objectStore(storename),request;
for(var i = 0 ; i < data.length;i++){
request = store.put(data[i]);
request.onerror = function(){
console.error('put添加數(shù)據(jù)庫中已有該數(shù)據(jù)')
};
request.onsuccess = function(){
console.log('put添加數(shù)據(jù)已存入數(shù)據(jù)庫')
};
}
},
getDataByKey:function(db,storename,key){
//根據(jù)存儲空間的鍵找到對應(yīng)數(shù)據(jù)
var store = db.transaction(storename,'readwrite').objectStore(storename);
var request = store.get(key);
request.onerror = function(){
console.error('getDataByKey error');
};
request.onsuccess = function(e){
var result = e.target.result;
console.log('查找數(shù)據(jù)成功')
console.log(result);
};
},
deleteData:function(db,storename,key){
//刪除某一條記錄
var store = store = db.transaction(storename,'readwrite').objectStore(storename);
store.delete(key)
console.log('已刪除存儲空間'+storename+'中'+key+'記錄');
},
clearData:function(db,storename){
//刪除存儲空間全部記錄
var store = db.transaction(storename,'readwrite').objectStore(storename);
store.clear();
console.log('已刪除存儲空間'+storename+'全部記錄');
}
}
var students=[{
id:1001,
name:"Byron",
age:24
},{
id:1002,
name:"Frank",
age:30
},{
id:1003,
name:"Aaron",
age:26
}];
INDEXDB.openDB(myDB.name,myDB.version);
setTimeout(function(){
console.log('****************添加數(shù)據(jù)****************************');
INDEXDB.addData(myDB.db,myDB.ojstore.name,students);
// console.log('******************add重復(fù)添加**************************');
// INDEXDB.addData(myDB.db,myDB.ojstore.name,students);
// console.log('*******************put重復(fù)添加*************************');
// INDEXDB.putData(myDB.db,myDB.ojstore.name,students);
// console.log('*******************獲取數(shù)據(jù)1001*************************');
// INDEXDB.getDataByKey(myDB.db,myDB.ojstore.name,1001);
// console.log('******************刪除數(shù)據(jù)1001************');
// INDEXDB.deleteData(myDB.db,myDB.ojstore.name,1001);
// console.log('******************刪除全部數(shù)據(jù)************');
// INDEXDB.clearData(myDB.db,myDB.ojstore.name);
// console.log('******************關(guān)閉數(shù)據(jù)庫************');
// INDEXDB.closeDB(myDB.db);
// console.log('******************刪除數(shù)據(jù)庫************');
// INDEXDB.deletedb(myDB.name);
},800)
</script>
</body>
</html>