zoukankan      html  css  js  c++  java
  • web API简介(四):客户端储存之IndexedDB API

    概述

    前篇:web API简介(三):客户端储存之Web Storage API

    客户端储存从某一方面来说和动态网站差不多。动态网站是用服务端来储存数据,而客户端储存是用客户端来储存数据。

    IndexedDB API就是现代HTML5客户端储存的方法之二。

    IndexedDB介绍

    IndexedDB是专门为大量结构化数据设计的。

    IndexedDB有这些特性

    (1)IndexedDB数据库储存的是键值对。

    (2)IndexedDB是基于事务型数据库模型的。

    (3)IndexedDB API是异步型的。

    (4)IndexedDB使用很多请求(requests)和响应。

    (5)IndexedDB使用DOM通知你,当结果被返回的时候。

    (6)IndexedDB数据库是对象型的数据库。

    (7)IndexedDB不使用SQL。

    (8)IndexedDB遵循同源政策。


    IndexedDB有这些限制

    (1)不支持international sorting。

    (2)不支持同步操作。你必须自己写同步操作代码。

    (3)不支持全文搜索的部分功能,比如SQL中的LIKE功能。

    储存限制

    indexedDB的Storage属性有2种:永久型和临时型。

    永久型数据没有任何限制,永久储存,只有当用户删除它的时候才会被删除。

    临时型数据有一个全局限制和同源限制。全局限制是指临时性数据的总量不能超过磁盘总量的50%。当超出的时候,浏览器会自动删除最久远被用到的数据,直到可以储存目前需要储存的数据。同源限制是指同源下的临时型数据总量有一个限制,这个限制是全局限制的20%,但不低于10M,且不超过2G。当超出同源限制的时候,浏览器会抛出一个错误。

    IndexedDB的使用模式

    和MongoDB的使用差不多,具体如下:

    (1)打开一个数据库。

    (2)在数据库中建立一个object store。

    (3)开始一项事务,并且用请求来操作数据库。

    (4)通过监听DOM事件等待事务完成。

    (5)利用返回的数据(request object)做一些操作。

    IndexedD的数据库操作

    检验是否支持IndexedDB

    if (!window.indexedDB) {
        window.alert("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
    }
    

    打开IndexedDB数据库

    我们发出一个打开数据库的请求。请求的result是一个IDBDatabase对象。

    var request = window.indexedDB.open("MyTestDatabase", 3);
    

    其中3是版本号。版本号不能用小数,否则会被四舍五入成整数。

    更新IndexedDB数据库版本

    在request发出后,onerror事件和onsuccess事件响应前,如果打开的IndexedDB数据库版本比已经存在的数据库版本低,那么就会出现onerror事件,如果如果打开的IndexedDB数据库版本比已经存在的数据库版本高,就会出现onupgradeneeded事件,在onupgradeneeded事件之后才出现success事件。

    var request = indexedDB.open(dbName, 2);
    
    //存在的数据库版本比2低的时候响应如下事件。
    request.onupgradeneeded = function(event) {
    
      //数据库在event.target的resule属性里面
      var db = event.target.result;
    
      //建立object store,并设立键值
      var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
    
      //设定object store的索引name,并设定为可以重复
      objectStore.createIndex("name", "name", { unique: false });
    
      //设定object store的索引email,并设定为不可以重复
      objectStore.createIndex("email", "email", { unique: true });
      };
    

    也可以利用autoIncrement设定一个自增长的键值。

    //建立object store,并设立自增长的键值,储存在key字段中
    var objectStore = db.createObjectStore("customers", { autoIncrement: true });
    

    等待IndexedDB数据库返回

    request.onerror = function(event) {
      alert("Why didn't you allow my web app to use IndexedDB?!");
    };
    request.onsuccess = function(event) {
      var db;
      db = event.target.result;
    };
    

    如果更新数据库版本,那么可以在onupgradeneeded事件里面进行增删改查操作,也可以在随后出现的onsuccess事件里面进行。

    如果不更新数据库版本,那么不会出现onupgradeneeded事件,这时只能在onsuccess事件里面进行增删改查操作。

    IndexedD的增删改查

    添加数据

    在进行增删改查的时候,我们都需要先给数据库增加一个事务,并且设定事务的状态:readonly,readwrite,和versionchange。

    var transaction = db.transaction(["customers"], "readwrite");
    

    transaction方法返回一个IDBTransaction对象,它具有一个方法:objectStore(),这个方法返回一个IDBObjectStore对象。

    var objectStore = transaction.objectStore("customers");
    customerData.forEach(function(customer) {
      var request = objectStore.add(customer);
      request.onsuccess = function(event) {
        // event.target.result === customer.ssn;
      };
    });
    

    IDBObjectStore对象的add()方法能够给自己添加数据,并且返回一个请求,这个请求的event.target.result是添加的数据。

    注意:add方法只能添加与原有数据不同key的数据,否则就用put方法。

    删除数据

    删除数据和添加数据类似。

    var request = db.transaction(["customers"], "readwrite")
                    .objectStore("customers")
                    .delete("444-44-4444");
    request.onsuccess = function(event) {
      // It's gone!
    };
    

    读取数据

    db.transaction("customers")
      .objectStore("customers")
      .get("444-44-4444")
      .onsuccess = function(event) {
      alert("Name for SSN 444-44-4444 is " + event.target.result.name);
    };
    

    注意:transaction默认使用readonly状态。

    读取并改写数据

    var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
    var request = objectStore.get("444-44-4444");
    
    request.onsuccess = function(event) {
      // Get the old value that we want to update
      var data = event.target.result;
    
      data.age = 42;
    
      var requestUpdate = objectStore.put(data);
    
       requestUpdate.onerror = function(event) {
         // Do something with the error
       };
       requestUpdate.onsuccess = function(event) {
         // Success - the data is updated!
       };
    };
    

    IndexedD的游标

    基本操作

    IDBObjectStore对象的openCursor()方法返回一个请求,这个请求的result就是这个游标本身。这个游标的key是原数据的键值,value是原数据。

    var objectStore = db.transaction("customers").objectStore("customers");
    
    objectStore.openCursor().onsuccess = function(event) {
      var cursor = event.target.result;
      if (cursor) {
        alert("Name for SSN " + cursor.key + " is " + cursor.value.name);
        cursor.continue();
      }
      else {
        alert("No more entries!");
      }
    };
    

    利用索引

    IDBObjectStore对象的index()方法返回一个打开了index的IDBObjectStore对象(把key设置为index里面的值,把value设置为原数据)。

    var index = objectStore.index("name");
    
    index.get("Donna").onsuccess = function(event) {
      alert("Donna's SSN is " + event.target.result.ssn);
    };
    

    openKeyCursor()方法

    IDBObjectStore对象的openCursor()方法返回一个请求,这个请求的result就是这个游标本身。这个游标的key是原数据的键值,value是原数据的主键。

    index.openKeyCursor().onsuccess = function(event) {
      var cursor = event.target.result;
      if (cursor) {
        // cursor.key is a name, like "Bill", and cursor.value is the SSN.
        // No way to directly get the rest of the stored object.
        alert("Name: " + cursor.key + ", SSN: " + cursor.primaryKey);
        cursor.continue();
      }
    };
    

    游标的范围和方向

    游标的范围是一个IDBKeyRange对象。

    游标的升降序和去重:next,prev,nextunique,prevunique。

    如下所示:

    // Only match "Donna"
    var singleKeyRange = IDBKeyRange.only("Donna");
    
    // Match anything past "Bill", including "Bill"
    var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");
    
    // Match anything past "Bill", but don't include "Bill"
    var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);
    
    // Match anything up to, but not including, "Donna"
    var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);
    
    // Match anything between "Bill" and "Donna", but not including "Donna"
    var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);
    
    objectStore.openCursor(boundKeyRange, "prevunique").onsuccess = function(event) {
      var cursor = event.target.result;
      if (cursor) {
        // Do something with the entries.
        cursor.continue();
      }
    };
    

    锁定数据库

    为了防止多人同时改写数据库,可以使用IDBDatabase对象的onblocked属性锁定数据库。

    var openReq = mozIndexedDB.open("MyTestDatabase", 2);
    
    openReq.onblocked = function(event) {
      // 如果有其它tab试图访问数据库,那么它们必须关闭否则我们不能继续。
      alert("Please close all other tabs with this site open!");
    };
      
    openReq.onupgradeneeded = function(event) {
      // All other databases have been closed. Set everything up.
      db.createObjectStore(/* ... */);
      useDatabase(db);
    };
      
    openReq.onsuccess = function(event) {
      var db = event.target.result;
      useDatabase(db);
      return;
    };
    
    function useDatabase(db) {
    
      db.onversionchange = function(event) {
        db.close();
        alert("A new version of this page is ready. Please reload!");
      };
    
      // Do stuff with the database.
    }
    
  • 相关阅读:
    WordCount项目基本功能
    让自己的头脑极度开放
    Docker安装Mysql5.7
    MySQL中的函数索引(Generated Column)及一次SQL优化
    关于老系统的重构和优化选择
    JIRA笔记(一):安装部署JIRA
    Jenkins 配置GitLab插件和Git插件
    Loading descriptor for XXX.'has encountered a problem' A internal error occured during:"Loading ....."
    Newton插值的C++实现
    Lagrange插值C++程序
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/8449010.html
Copyright © 2011-2022 走看看