IndexedDB存储机制

IndexedDB存储与WebSQL存储的比较及选择

IndexedDB

IndexedDB 是一种可以让你在用户的浏览器内持久化存储数据的方法。IndexedDB 为生成 Web Application 提供了丰富的查询能力,使我们的应用在在线和离线时都可以正常工作。IndexedDB里数据以对象的形式存储,每个对象都有一个key值索引。IndexedDB里的操作都是事务性的。一种对象存储在一个objectStore里,objectStore就相当于关系数据库里的表。IndexedDB可以有很多objectStore,objectStore里可以有很多对象。每个对象可以用key值获取。

特点:

  1. 使用NoSQL数据库
  2. 支持事务、游标、索引等数据库操作
  3. 一般浏览器会分配50M-250M不等的内存
  4. 持久化存储,清除浏览器缓存不会被删除(localStorage是会被删除的)
  5. 支持多种数据格式:arrayBuffer、String、Object、Array、File、Blob、ImageData都ok
  6. 不支持跨域,一个域可以有多个数据库
  7. 开发中需要谨记的一个特性:异步操作,换句话说,所有操作都需要在回调函数中完成
  8. 存储空间大,IndexedDB的存储空间比localStorage大得多,一般来说不少于250MB。IE的储存上限是250MB,Chrome和Opera是硬盘剩余空间的某个百分比,Firefox则没有上限。

浏览器支持:

  1. IE10+
  2. Firefox 10+、Chrome 23+、Opera 15+
  3. iPhone ios8-ios10 safari支持(X5内核不支持)
  4. Android X5内核支持

WebSQL

Web SQL Database API 实际上并不包含在 HTML5 规范之中。它是一个独立的规范,它引入了一套使用 SQL 操作客户端数据库的 API。最新版本的 Chrome,Safari 和 Opera 浏览器都支持 Web SQL Database。

特点:

  1. 使用MySQL数据库
  2. 相比传统存储,能方便的进行对象存储,能进行大量的数据的处理
  3. w3c规范已经不再支持
  4. 浏览器支持较差,Web Sql API的主要实现者是Chrome、Safari、Opera、Android、IOS、BB。IE和FF都不支持Web Sql API。

比较

  1. IndexedDB对浏览器的兼容性比WebSQL更好
  2. WebSQL已经被w3c规范摒弃

创建IndexedDB数据库

调用indexedDB.open方法就可以创建或者打开一个indexedDB。代码中定义了一个myDB对象,在创建indexedDB request的成功毁掉函数中,把request获取的DB对象赋值给了myDB的db属性,这样就可以使用myDB.db来访问创建的indexedDB了。

function openDB (name) {
    var request=window.indexedDB.open(name);
    request.onerror=function(e){
        console.log('OPen Error!');
    };
    request.onsuccess=function(e){
        myDB.db=e.target.result;
    };
}

var myDB={
    name:'test',
    version:1,
    db:null
};
openDB(myDB.name);

我们注意到除了onerror和onsuccess,IDBOpenDBRequest还有一个类似回调函数句柄——onupgradeneeded。这个句柄在我们请求打开的数据库的版本号和已经存在的数据库版本号不一致的时候调用。
indexedDB.open()方法还有第二个可选参数,数据库版本号,数据库创建的时候默认版本号为1,当我们传入的版本号和数据库当前版本号不一致的时候onupgradeneeded就会被调用,当然我们不能试图打开比当前数据库版本低的version,否则调用的就是onerror了,修改一下刚才例子

function openDB (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){
        myDB.db=e.target.result;
    };
    request.onupgradeneeded=function(e){
        console.log('DB version changed to '+version);
    };
}

var myDB={
    name:'test',
    version:3,
    db:null
};
openDB(myDB.name,myDB.version);

关闭与删除数据库

关闭数据库可以直接调用数据库对象的close方法

function closeDB(db){
    db.close();
}

删除数据库使用indexedDB对象的deleteDatabase方法

function deleteDB(name){
    indexedDB.deleteDatabase(name);
}

object store

有了数据库后我们自然希望创建一个表用来存储数据,但indexedDB中没有表的概念,而是objectStore,一个数据库中可以包含多个objectStore,objectStore是一个灵活的数据结构,可以存放多种类型数据。也就是说一个objectStore相当于一张表,里面存储的每条数据和一个键相关联。我们可以使用每条记录中的某个指定字段作为键值(keyPath),也可以使用自动生成的递增数字作为键值(keyGenerator),也可以不指定。选择键的类型不同,objectStore可以存储的数据结构也有差异。

给object store添加数据

因为对新数据的操作都需要在transaction中进行,而transaction又要求指定object store,所以我们只能在创建数据库的时候初始化object store以供后面使用,这正是onupgradeneeded的一个重要作用。这样在创建数据库的时候我们就为其添加了一个名为students的object store,准备一些数据以供添加。

function openDB (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){
        myDB.db=e.target.result;
    };
    request.onupgradeneeded=function(e){
        var db=e.target.result;
        if(!db.objectStoreNames.contains('students')){
            db.createObjectStore('students',{keyPath:"id"});
        }
        console.log('DB version changed to '+version);
    };
}

var students=[{ 
    id:1001, 
    name:"Byron", 
    age:24 
},{ 
    id:1002, 
    name:"Frank", 
    age:30 
},{ 
    id:1003, 
    name:"Aaron", 
    age:26 
}];

function addData(db,storeName){
    var transaction=db.transaction(storeName,'readwrite'); 
    var store=transaction.objectStore(storeName); 

    for(var i=0;i<students.length;i++){
        store.add(students[i]);
    }
}


openDB(myDB.name,myDB.version);
setTimeout(function(){
    addData(myDB.db,'students');
},1000);

查找数据

可以调用object store的get方法通过键获取数据,以使用keyPath做键为例

function getDataByKey(db,storeName,value){
    var transaction=db.transaction(storeName,'readwrite'); 
    var store=transaction.objectStore(storeName); 
    var request=store.get(value); 
    request.onsuccess=function(e){ 
        var student=e.target.result; 
        console.log(student.name); 
    };
}

更新数据

可以调用object store的put方法更新数据,会自动替换键值相同的记录,达到更新目的,没有相同的则添加,以使用keyPath做键为例

function updateDataByKey(db,storeName,value){
    var transaction=db.transaction(storeName,'readwrite'); 
    var store=transaction.objectStore(storeName); 
    var request=store.get(value); 
    request.onsuccess=function(e){ 
        var student=e.target.result; 
        student.age=35;
        store.put(student); 
    };
}

删除数据及object store

调用object store的delete方法根据键值删除记录

function deleteDataByKey(db,storeName,value){
    var transaction=db.transaction(storeName,'readwrite'); 
    var store=transaction.objectStore(storeName); 
    store.delete(value); 
}

调用object store的clear方法可以清空object store

function clearObjectStore(db,storeName){
    var transaction=db.transaction(storeName,'readwrite'); 
    var store=transaction.objectStore(storeName); 
    store.clear();
}

调用数据库实例的deleteObjectStore方法可以删除一个object store,这个就得在onupgradeneeded里面调用了

if(db.objectStoreNames.contains('students')){ 
    db.deleteObjectStore('students'); 
}