• Web数据持久化存储IndexedDB(不常用)


    IndexedDB是在浏览器中保存结构化数据的一种数据库,为了替换WebSQL(标准已废弃,但被广泛支持)而出现。IndexedDB使用NoSQL的形式来操作数据库,保存和读取是JavaScript对象,同时还支持查询及搜索。

    下面由5个方面讲述:

    1. 数据库初始化

    2. 对象存储空间(ObjectStore)

    3. 事务

    4. 游标查询

    5. 索引

    数据库初始化

    IndexedDB保存的是对象,而不是使用表保存数据。打开数据库使用indexDB.open方法,这方法有两个参数,第一个是数据库名称,第二个是数据版本号。

    PS:IndexedDB的操作完全是异步进行的,每一次IndexedDB操作,都需要注册onerror或onsuccess事件处理程序。

         var DB_NAME = 'DEMO';
         var DB_VERSION = 2; //使用正整数,别用浮点型
         var db;
     
         function initDb() {
              console.debug("initDb ...");
              var req = indexedDB.open(DB_NAME, DB_VERSION);
              req.onsuccess = function (evt) {
                   db = evt.target.result;
                   console.debug("initDb opened");
              };
              req.onerror = function (evt) {
                   console.error("initDb error:", evt.target.errorCode || evt.target.error);
              };
     
              //增加数据库版本号时,会触发onupgradeneeded事件(会在onsuccess之前被调用)
              req.onupgradeneeded = function (evt) {
                   console.debug("initDb.onupgradeneeded");
              };
         }

    PS:这里要注意的是,数据库版本只会有最新一个,不会同时存在两个版本的同名数据库。

    对象存储空间(ObjectStore)

    对象存储空间(ObjectStore)可以想象成关系数据库的表,在初始化DB触发onupgradeneeded时,创建ObjectStore。使用createObjectStore方法,第一个参数是对象名,第二个参数是对象属性,一般是设置keyPath(作为键使用)。

         req.onupgradeneeded = function (evt) {
              console.debug("initDb.onupgradeneeded");
              var db = evt.currentTarget.result;
              //ObjectStore必须在onupgradeneeded里创建,其他地方将会创建失败
              var usersStore = db.createObjectStore("users", { keyPath : "id" });
         };

    效果如下:

    事务

    所有读取或修改数据的操作,都要通过事务来完成。创建事务使用transaction方法,第一个参数是需要访问的ObjectStore,第二个参数是访问模式(readwrite、readonly,默认是只读)。

    添加数据

    function addData(){
         var users = [{
              id : '001',
              name : '刘亦菲',
              age : 18
         },{
              id : '002',
              name : '杨幂',
              age : 19
         }];
     
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var i = 0, len = users.length;
         while(i < len){
              store.add(users[i++]);
         }
    }

    获取数据

    function getData(){
         var tx = db.transaction("users");
         var store = tx.objectStore("users");
         var req = store.get("001");
         req.onsuccess = function (evt) {
              var res = evt.target.result;
              console.debug(res);
         };
         req.onerror = function (evt) {
              console.error("getData error:", evt.target.errorCode || evt.target.error);
         };
    }

    修改数据

    function updateData(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var req = store.put({
              id : '001',
              name : '刘亦菲-小龙女',
              age : 18
         });
         req.onsuccess = function (evt) {
              console.debug("updateData success");
         };
         req.onerror = function (evt) {
              console.error("updateData error:", evt.target.errorCode || evt.target.error);
         };
    }

    删除数据

    function delData(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var req = store.delete("001");
         req.onsuccess = function (evt) {
              console.debug("delData success");
         };
         req.onerror = function (evt) {
              console.error("delData error:", evt.target.errorCode || evt.target.error);
         };
    } 

    清空数据

    function clearData(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var req = store.clear();
         req.onsuccess = function (evt) {
              console.debug("clearData success");
         };
         req.onerror = function (evt) {
              console.error("clearData error:", evt.target.errorCode || evt.target.error);
         };
    }

    游标查询

    使用事务可以直接通过键检索单个对象,而需要检索多个对象时候就需要使用游标。游标是指向结果集的指针,不提前收集结果。游标指针会先指向结果中的第一项,在接到查找下一项指令时,才会指向下一项。

    function openCursor(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var req = store.openCursor();
         req.onsuccess = function (evt) {
              var cursor = evt.target.result;
              if(cursor){ //必要检查
                   var value = cursor.value;
                   console.log(value);
                   if(value.name == '杨幂'){
                        value.age = 16;
                        cursor.update(value); //修改数据(必须是读写模式)
                   }
                   if(value.name == '柳岩'){
                        cursor.delete();  //删除当前项
                   }
                   cursor.continue(); //移动到下一项
              }
         };
         req.onerror = function (evt) {
              console.error("openCursor error:", evt.target.errorCode || evt.target.error);
         };
    }

    这里有几点要注意:

    1. 如果需要修改或删除数据,就需要打开成读写模式。

    2. cursor的非空校验是必要的。

    3. 修改或删除的操作也是有onsuccess和onerror的,只是在示例中没有写出来。

    4. 调用continue才会移动到下一项

    另外可以设置游标的键范围和游标的方向,即打开openCursor方法时可以传这两个参数(openCursor(键范围,方向)),第一个参数是object类型,第二个参数是字符串类型。

    游标键范围

    键范围由IDBKeyRange的实例表示。

    IDBKeyRange.only('001');  //只想要键为001的结果
    IDBKeyRange.lowerBound('002'); //从键为002开始,到最后
    IDBKeyRange.lowerBound('002', true); //从键为002开始,但忽略002,到最后
    IDBKeyRange.upperBound('002'); //从头开始,到键为002为止
    IDBKeyRange.upperBound('002', true); //从头开始,到键为002为止,但忽略002
    IDBKeyRange.bound('001', '005'); //从001开始,到为005为止
    IDBKeyRange.bound('001', '005', true, true); //从001开始,到为005为止,但忽略001、005

    游标方向

    next : 从第一项到最后一项(默认)

    prev : 从最后一项到第一项

    索引

    当需要使用其他属性(非主键)获取数据时,就要预先创建索引,然后使用索引获取数据。

    创建索引(在数据库初始化onupgradeneeded事件时)

    第一个参数是索引名字,第二个参数是索引的属性的名字,第三个是一个options对象。一般是指定unique,设置索引是否唯一。

    usersStore.createIndex("name", "name", { unique : false });

    索引获取数据

    function indexGetData(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var index = store.index("name");
         var req = index.get("杨幂")
         req.onsuccess = function (evt) {
              console.debug("indexGet success" , evt.target.result);
         };
         req.onerror = function (evt) {
              console.error("indexGet error:", evt.target.errorCode || evt.target.error);
         };
    }
    
    function indexOpenCursor(){
         var tx = db.transaction("users", READ_WRITE);
         var store = tx.objectStore("users");
         var index = store.index("name");
         var req = index.openCursor();
         req.onsuccess = function (evt) {
              var cursor = evt.target.result;
              if(cursor){ //必要检查
                   var value = cursor.value;
                   console.log(value);
                   cursor.continue(); //移动到下一项
              }
         };
         req.onerror = function (evt) {
              console.error("openCursor error:", evt.target.errorCode || evt.target.error);
         };
    }

    PS:索引用法跟普通取值和游标取值一样

    对象存储所有索引

    function indexNames(){
         var tx = db.transaction("users", READ_WRITE);
        var store = tx.objectStore("users");
         var indexNames = store.indexNames;
         var index, i = 0, len = indexNames.length;
         while(i < len){
              index = store.index(indexNames[i++]);
              console.log(index);
         }
    }

    浏览器支持情况

    PS:图表来源->http://caniuse.com/#feat=indexeddb

    总结

    在使用IndexedDB时候,有人可能会拿WebSQL来比较,然后发现IndexedDB不能做表连接(因为根本没有这东西),也就是要查出一个数据,可能得分几次进行。

    例如学生、课程、分数三个表数据,想查出某个学生的课程成绩,就得三个表连接,WebSQL分分钟信手拈来。但是如果你用IndexedDB,就得分三次查找,先拿出那个学生,再拿出课程,然后再拿成绩。

    这样看起来IndexedDB很蠢,这样就进入误区了,你为什么要这么去存你要展示的数据,NoSql就用NoSql东西,就直接以一个对象存学生成绩,一次查找就行了。

    示例下载:http://files.cnblogs.com/files/lovesong/IndexedDBdemo.zip

    本文为原创文章,转载请保留原出处,方便溯源,如有错误地方,谢谢指正。

    本文地址 :http://www.cnblogs.com/lovesong/p/5055384.html

  • 相关阅读:
    MySql-数据库基础
    Window安装MySQL
    Python程序中的进程操作-进程间通信(multiprocess.Queue)
    线程
    上传电影代码
    并发编程基础
    基于socketserver实现并发的socket编程
    模拟ssh远程执行命令
    GIT的使用,Pycharm中使用GitHub
    主机如何访问运行在虚拟机中的Django项目
  • 原文地址:https://www.cnblogs.com/lovesong/p/5055384.html
Copyright © 2020-2023  润新知