现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景
IndexedDB有以下几个特点
(1)键值对储存: IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓库中,数据以"键值对"的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
(2)异步: IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他操作,这与 LocalStorage 形成对比,后者的操作是同步的。异步设计是为了防止大量数据的读写,拖慢网页的表现。
(3)支持事务: IndexedDB 支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况。
(4)同源限制: IndexedDB 受到同源限制,每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
(5)储存空间大: IndexedDB 的储存空间比 LocalStorage 大得多,一般来说不少于 250MB,甚至没有上限。
(6)支持二进制储存: IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象)。
名称 | 属性 | 描述 |
---|---|---|
数据库 | IDBDatabase 对象 | 数据库是一系列相关数据的容器。每个域名(严格的说,是协议 + 域名 + 端口)都可以新建任意多个数据库。IndexedDB 数据库有版本的概念。同一个时刻,只能有一个版本的数据库存在。如果要修改数据库结构(新增或删除表、索引或者主键),只能通过升级数据库版本完成。 |
对象仓库 | IDBObjectStore 对象 | 每个数据库包含若干个对象仓库(object store)。它类似于关系型数据库的表格。 |
索引 | IDBIndex 对象 | 为了加速数据的检索,可以在对象仓库里面,为不同的属性建立索引。 |
事务 | IDBTransaction 对象 | 在对新数据库做任何事情之前,需要开始一个事务。事务中需要指定该事务跨越哪些object store。事务有3种模式:1)只读 : read;2) 读写:readwrite;3)版本变更:verionchange |
操作请求 | IDBRequest 对象 | |
指针 | IDBCursor 对象 | |
主键集合 | IDBKeyRange 对象 |
/*
* @param String dataBaseName 数据库的名字
* @param Number version 数据库版本号,如果省略,在打开已有数据库时,默认为当前版本号,新建数据库时,默认为1.
*/
var request = window.indexedDB.open(dataBaseName, version);
indexedDB.open() 方法返回一个IDBRequest 对象。这个对象通过error 、success、upgradeneeded三个事件,处理打开数据库的操作结果。
(1)error事件:表示打开数据库失败。
request.onerror = function(event){
console.log('数据库打开失败');
}
(2)success事件:表示成功打开数据库
var db;
request.onsuccess = function(event){
db = request.result;
console.log('数据库打开成功');
}
(3)upgradeneeded事件:新建数据库或者当指定的版本号大于数据库实际版本号,就会发生数据库升级事件,此时会调用upgradeneeded事件。
var db;
request.onupgradeneeded = function(event){
db = event.target.result;
var objectStore;
//判断class表格是否存在
if (!db.objectStoreNames.contains('class')){
//创建一个叫class的表格,主键是id
ojbectStore = db.createObjectStore('class',{keyPath:'id'});
}
}
如果数据记录里面没有合适作为主键的属性,那么可以让IndexedDB自动生成主键。
代码如下:
//创建一个objectStore名字叫class,指定主键为一个递增的整数。
var objectStore = db.createObjectStore('class',{autoIncrement:true});
新建对象仓库以后,下一步可以新建索引
/*
* @param name 索引名称
* @param proto 索引所在的属性
* @param object 配置对象,说明该属性是否包含重复的值
*/
IDBObject.createIndex(name,proto,object);
var db;
request.onupgradeneeded = function(event){
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('class')){
ojbectStore = db.createObjectStore('class',{keyPath:'id'});
}
//新建索引
objectStore.createIndex('name', 'name', {unique : false});
objectStore.createIndex('email', 'email', {unique : true});
}
var testIDB = {
name : 'class',
version : 1,
db : null
}
/*
*@param name 数据库名称
*@param version 版本号
*/
function openIDB (name,version) {
var version=version || 1;
var request=window.indexedDB.open(name,version);
request.onerror=function(e){
console.log(e.currentTarget.error.message);
};
request.onsuccess=function(e){
testIDB.db=e.target.result;
};
request.onupgradeneeded=function(e){
var db=e.target.result;
if(!db.objectStoreNames.contains('classOne')){
db.createObjectStore('classOne',{keyPath:"id"});
}
console.log('DB version changed to '+version);
};
}
//准备一些数据
var students = [
{id:1,name:'sai',age:28,height:189,weight:65},
{id:2,name:'zhang',age:22,height:140,weight:44},
{id:3,name:'yao',age:26,height:150,weight:74}
];
/*
*添加数据到数据库
*@param Array db
*@param String storeName
*@param Array data
*/
function addData(db,storeName,data){
//打开一个事务
var transaction=db.transaction(storeName,'readwrite');
//获取objectStore
var store=transaction.objectStore(storeName);
for(var i=0; i < data.length; i++){
//往objectStore添加数据
store.add(data[i]);
}
}
openIDB(testIDB.name,testIDB.version);
//由于异步API原因,不能保证能够在addData方法调用前获取db对象(实际上获取db对象也比执行一条语句慢得多),所以此处用了延时。
setTimeout(function(){
addData(testIDB.db, 'classOne', students);
},1000);
/*
*查找数据
*@param Array db
*@param String storeName
*@param String value
*/
function getData(db,storeName,value){
//打开一个事务
var transaction = db.transaction(storeName,'readwrite');
//获取objectStore
var store = transaction.objectStore(storeName);
//通过get方法获取数据
var request=store.get(value);
request.onsuccess=function(e){
var student=e.target.result;
console.log(student);
};
}
getData(testIDB.db,'classOne',1);
//{id: 1, name: "sai", age: 28, height: 189, weight: 65}
/*
*更新数据
*@param Array db
*@param String storeName
*@param String keyPath
*@param String updateValue
*/
function updateDataByKey(db, storeName, keyPath, updateValue){
//打开一个事务
var transaction = db.transaction(storeName,'readwrite');
//获取objectStore
var store = transaction.objectStore(storeName);
var request = store.get(keyPath);
request.onsuccess = function(e){
var student = e.target.result;
student.age = updateValue;
store.put(student);
};
}
//更新classOne表格id=1的age数据为222
updateDataByKey(testIDB.db,'classOne',1,222);
getData(testIDB.db,'classOne',1);
//{id: 1, name: "sai", age: 222, height: 189, weight: 65}
/*
*按照keyPath删除数据
*@param Array db
*@param String storeName
*@param String keyPath
*/
function deleteDataByKey(db,storeName,keyPath){
//打开一个事务
var transaction = db.transaction(storeName,'readwrite');
//获取objectStore
var store = transaction.objectStore(storeName);
//按照keyPath值删除数据
store.delete(keyPath);
}
//删除名字为classOne的storeObject里keyPath为1的数据
deleteDataByKey(testIDB.db, 'classOne', 1);
/*
*清空objectStore里面所有数据
*@param Array db
*@param String storeName
*/
function clearObjectStore(db,storeName){
//打开一个事务
var transaction=db.transaction(storeName,'readwrite');
//获取objectStore
var store=transaction.objectStore(storeName);
//清空classOne表格里所有数据
store.clear();
}
//清空classOne里面所有数据
clearObjectStore(testIDB.db,'classOne');
在onupgradeneeded里面,调用数据库实例的deleteObjectStore方法,可以删除一个object store。
//删除classOne表格
if (db.objectStoreNames.contains('classOne')){
db.deleteObjectStore('classOne');
}
function openIDB (name,version) {
var version=version || 1;
var request=window.indexedDB.open(name,version);
request.onerror=function(e){
console.log(e.currentTarget.error.message);
};
request.onsuccess=function(e){
testIDB.db=e.target.result;
};
request.onupgradeneeded=function(e){
var db=e.target.result;
if(!db.objectStoreNames.contains('classOne')){
var store = db.createObjectStore('classOne',{keyPath:"id"});
/*
*创建索引
*@param nameIndex 索引名称
*@param name 索引属性字段名
*@param Object 索引属性值是否唯一
*/
store.createIndex('nameIndex','name',{unique:true});
store.createIndex('ageIndex','age',{unique:false});
}
console.log('DB version changed to '+version);
};
}
此处需要刷新才会出来效果哦