HTML5项目笔记5:使用HTML5 WebDataBase设计离线数据库

2019-03-28 20:12|来源: 网络

基于HTML5的Web DataBase 可以让你在浏览器中进行数据持久地存储管理和有效查询,假设你的离线应用程序有需要规范化的存储功能,那么使用Web DataBase,可以使你的应用程序无论是在离线或者在线或者网络不通畅情况下都可以将数据保存在客户端。

下面是HTML5 DataBase中两个不同的DataBase的比较,摘自http://www.html5rocks.com/en 上面的一篇文章。

我们这边使用WebSQL来设计和编写底层服务,W3C WebDatabase 规范中说这份规范不再维护了,但是几乎实现者都选择了SQLite这种轻量简单易用的客户端数据库:

现在我们来封装和提取WebSQL公用方法。

首先,我们需要拿到SQLite数据库可操作和执行的SQL数据上下文:

 

这边通过openDatatBase方法打开或创建数据库:

/*-------执行SQLite注入,数据库的基本操作(Begin)-------*/
function SQLProvider(dbName, size) {
    this.dbName = dbName || 'OFLMAIL';
    var db = openDatabase(this.dbName, '1.0', 'database for ' + 
        this.dbName, (size || 2) * 1024 * 1024);
    this.db = db;
    /*-------执行SQLite注入,数据库的基本操作(End)-------*/
    function sqlerrorHandler(tx, e) {
        log.error(e.message);
    }


这边还可以设置数据库的名称dbName和数据库大小size,默认数据库名称是OFLMAIL,就是我们这个离线系统的名称,默认大小是2兆。

我们还可以设置错误处理方法sqlErrorHandler,用户处理操作失败之后的错误捕捉

这样,我们就拿到了操作SQLite的数据上下文db,通过上下文db,我们可以执行相应的CURD操作。

第一步,我们写一个创建数据表的方法,把这个方法放在SQLProvider方法体里面,

/*--添加数据表--*/
this.createTable = function (tableName, fields, callBack) {
    var pkField = tableName + "_SEC";
    var sql = "CREATE TABLE IF NOT EXISTS " + tableName + "( " + 
        pkField + " integer primary key autoincrement,";
 
        // 合并字段串同时去除传入的主键字段
        sql += fields.join(",").replace(pkField + ",", "") + ")";
        //log.debug(sql);
 
        db.transaction(function (tx) {
            tx.executeSql(sql, [], function () {
                if (callBack) callBack();
            }, sqlerrorHandler);
        })
    }


一共包含了三个参数tableNamefiledscallBack,分表代表你要创建的表名,所对应的字段数组,就是把这个表相应的字段用数组保存起来(方法里面还会自动创建一个表名加上“_SEC”的字段,他是个增量标识,用做主键)callBack顾名思义,回调函数,这个参数可以不传。这个回调函数的存在很重要,因为整个基于SQLite数据库的操作方法都是异步调用的,所以需要在回调函数中嵌套执行,否则有些执行会被中断。

将这个函数放在SQLProvider里面,有一个好处就是到时候可以在SQLProvider的动态实例化中直接调用该函数

如:var sqlProvider = new SQLProvider();

sqlProvider.createTable(“UserInfo”,new Array(“UserName”,”UserPwd”));

这样子,方便我们在页面中调用。这种操作方法相当于C#里面的动态类创建方法,SQLProvider就是类名,createTable就是类中的方法,实例化调用。

接下来我们的数据库的操作,包括数据表和数据的CURD操作,都会以这种方法写在里面:

删除数据表(只需传入表名就行了,他会删除相应的数据表):


/*--删除数据表--*/
this.dropTable = function (tableName) {
    var sql = "DROP TABLE " + tableName;
    db.transaction(function (tx) {
        tx.executeSql(sql);
    })
}

添加数据(包含了四个参数:表名,字段数组,字段所对应的值的数组,和一个回调函数)

这边的fields和values代表了字段数组和值数组,他们一一对应:

如 var fileds=new Array(“UserName”,”UserPwd”);

  var values=new Array(“Ben”,”123456”);则说明在UserInfo表里面添加了一条数据,这条数据至少包含三个有值的字段,主键,UserName和UserPwd,而values 则是相应的值数组。

  回调函数中带有一个返回的参数,返回了你所添加的改行数据的主键。

/*--添加数据(插入数据)--*/
    this.insertRow = function (tableName, fields, values, callback) {
        var sql = "INSERT INTO " + tableName + " (" + fields.join(",") + ") SELECT "
         + new Array(values.length + 1).join(",?").substr(1);
 
        db.transaction(function (tx) {
            tx.executeSql(sql, values, function () { }, sqlerrorHandler);
            //log.debug(sql);
 
            tx.executeSql("SELECT max(" + tableName + "_SEC) id from " + 
                    tableName, [], function (tx, result) {
                var item = result.rows.item(0);
                var id = parseInt(item.id);
                //log.debug("id=" + id);
                if (callback) callback(id);
            }, sqlerrorHandler);
        });
    }

删除数据 (包含了三个参数:表名tableName,主键sec和一个回调函数callback)

这个主键SEC是该待删除的数据在Web DataBase中的主键,我们前面在建表的时候有一个增量标识字段,该字段的名称为表名加上“_SEC”,因为唯一性,所以我们可以根据这个主键来删除该行数据,

代码如下:

/*--删除数据--*/
    this.deleteRow = function (tableName, sec,callback) {
        var pkField = tableName + "_SEC";
        var sql = "DELETE FROM " + tableName + " WHERE " + pkField + " = ?";
        db.transaction(function (tx) {
            tx.executeSql(sql, [sec], null, sqlerrorHandler);
            if (callback) callback(); //使用回调 
        })
    }


修改数据(这边包括了四个参数,表名tableName,字段数组fields,值数组values,回调函数callback)

字段数组和值数组必须是一一对应的,而且第一个字段必须是主键,所对应的values的第一个值也必须是主键的值,这样,可以根据字段的主键来查询相应的数据行。

查出的数据行之后,可以根据后面的相应字段,进行修改。

/*--更新列,这边需要注意的是两个参数列表的首位必须是主键(或者说第一个必须是条件,后面的是修改位)--*/
    this.updateRow = function (tableName, fields, values,callback) {
        var len = fields.length;
 
        var sql = "";
        for (i = 1; i < len; i++) {
            if (i == 1) sql += fields[i] + " = '" + values[i] + "'";
            else sql += "," + fields[i] + " = '" + values[i] + "'";
        }
 
        sql = 'UPDATE ' + tableName + ' SET ' + sql + ' where ' + fields[0] + '= ?';
        //log.debug("sql:" + sql);
 
        db.transaction(function (tx) {
            tx.executeSql(sql, [values[0]],
             null, sqlerrorHandler);
            //log.debug("update " + tableName + " success! sec=" + values[0]);
            if (callback) callback();
        });
    }
}


调用方式类似如下:

var fileds=new Array(“UserInfo_SEC”,“UserName”,”UserPwd”);

var values=new Array(“5”,“Ben”,”123456”);

sqlProvider.updateRow(“UserInfo”,fileds ,values,function(){

 log.debug(“修改成功!”);

});

这样子就是在UserInfo表里面修改主键为5的数据行,修改它的UserName的值为:“Ben”,

修改它的UserPwd的值为:“123456”

根据主键查询单行数据(包含三个参数表名tableName,主键SEC,回调函数callback):

根据表名和主键名称获取到该行数据,并返回,注意到这边通过cllback回调函数来返回查询的结果,通过数据上下文tx执行该SQL脚本,返回的是结果集result,这边我们取他结果集的第一条数据也即是result.rows.item(0),实际上结果集中也只有一条数据。

/*--读取单行数据--*/
    this.readRow = function (tableName, sec, callback) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_SEC = ?', [sec], function (tx, result) {
                if (callback) callback(result.rows.item(0)); // 使用回调  
            }, sqlerrorHandler);
        });
    }


读取指定的数据表(根据表名来读取相应的数据表,并返回结果集):


/*--读取数据表--*/
    this.loadTable = function (tableName, callback) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * from ' + tableName, [], function (tx, result) {
                if (callback) callback(result); //使用回调                
            }, sqlerrorHandler);
        });
    }


结果集result中的列的集合用result.rows表示

列的数量用result.rows.length来表示

单条数据是用result.rows.item(index)表示,index指的是列的索引位置,从0开始

根据SQL的where条件语句来读取指定的数据表(根据表名tableName和sqlSenten条件语句来执行,并返回结果集):


/*--根据查询条件读取数据表--*/
    this.loadTableBySQl = function (tableName, sqlSenten, callback) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * from ' + tableName+" WHERE "+ sqlSenten, [], function (tx, result) {
                if (callback) callback(result); //使用回调                
            }, sqlerrorHandler);
        });       
    }


与上面的方法类似,只是多了一个sqlSenten条件语句来筛选数据

根据某个字段检查是否存在该列(通过字段名和字段所对应的值)来进行操作,过多地用于根据主键来查询数据行:


/*--检查是否已存在该列--*/
    this.checkExist = function (tableName, fieldName, fieldValue, callback) {
        db.transaction(function (tx) {
            tx.executeSql('SELECT * from ' + tableName + ' where ' + fieldName + '= ?', [fieldValue], function (tx, result) {
                var isExist;
                if (result.rows.length == 1) isExist = "1"; else isExist = "0"; //1代表存在该行,0 代表不存在该行
                if (callback) callback(isExist);
            }, sqlerrorHandler);
        });
    }


当检索读到的结果集合中包含了一条数据的时候,返回1,代表存在该行,为0的时候代表不存在该行。这边做的其实不完善只能在唯一值的字段中才能够过正确显示,如主键,此外还可以通过where条件语句来验证是否存在该行。这边就不说了,自己去尝试。

这样就完成了整个离线数据库的CURD操作,如果有不够的地方,我们可以继续修改完善,完整代码如下,在代码的结尾我们进行了实例化,我们把这些代码独立地存放到WebDataBase.js文件里面,这样可以在继承这个脚本文件的页面里直接调用这个脚本库的方法。

现在我们把这些数据库的的操作应用到我们的系统中,

我们的用户信息页面(Information.html),用来保存登录用户的个人信息的:

包含了如下字段:姓名,性别,入职时间,工号和部门:

在载入的时候查看是否有数据,有数据则显示第一条

$(document).ready(function () {
            sqlProvider.loadTable("UserInfo", function (result) {
                // result.rows 获取到所有数据行
                if (result.rows.length > 0) {
                    var row = result.rows.item(0);
                    $("#UserName").val(row.UserName);
                    $("#UserSex").val(row.UserSex);
                    $("#ReportDutyTime").val(row.ReportDutyTime);
                    $("#JobNumber").val(row.JobNumber);
                    $("#DepartmentNumber").val(row.DepartmentNumber);
                  //这边包含一个隐藏域,可以保存该用户信息的主键  
                  $("#UserInfo_SEC").val(row.UserInfo_SEC);
                }
            })
        })


我们的保存按钮的代码如下:

function onformsumit() 
    {
    //创建用户信息表(存在跳过,不存在创建),包含六个字段,
    //因为创建的时候会自动创建一个UserInfo_SEC的主键,所以实际上是6个字段
    //UserName:用户名称
    //UserSex:用户性别
    //ReportDutyTime:入职时间
    //JobNumber:工号
    //DepartmentNumber:部门
    //Remark:备注
     
     
    var UserName = $("#UserName").val();
    var UserSex = $("#UserSex").val();
    var ReportDutyTime = $("#ReportDutyTime").val();
    var JobNumber = $("#JobNumber").val();
    var DepartmentNumber = $("#DepartmentNumber").val();
    var Remark = "";
 
    var fields = new Array("UserName", "UserSex", "ReportDutyTime", 
        "JobNumber", "DepartmentNumber", "Remark");
    var values = new Array(
        UserName,UserSex,ReportDutyTime,JobNumber,DepartmentNumber,Remark);
    sqlProvider.createTable("UserInfo", fields, function () {
    log.debug("创建数据表UserInfo");
 
     var UserInfo_SEC = $("#UserInfo_SEC").val();
     //取隐藏域的值,如果是0则为保存不为0则为修改
     if (UserInfo_SEC == "0") {
          sqlProvider.insertRow("UserInfo", fields, values, function () {
              log.debug("插入数据成功!");
              alert("保存成功!");
          });
      }else {
          sqlProvider.updateRow("UserInfo", fields, values, function () {
               log.debug("修改数据成功!");
               alert("保存成功!");
          });
      }
    });
    return false;
}


保存成功之后,数据就存储在我们离线的数据库里面了,载入时显示在页面效果如下:

我们去浏览器中的DataBase中查看,就可以看到这条数据了,如图:

    //以下是表单重置函数,删掉该用户信息的代码

     function resets() {

         var UserInfo_SEC = $("#UserInfo_SEC").val();

         if (UserInfo_SEC != "0") {

             sqlProvider.deleteRow("UserInfo", UserInfo_SEC, function () {

                 window.location.reload(true);

             })

         }

     }

2010.11.18, W3C 宣布 将不再关注Web SQL databas,并且不再维护它的过时的规范,浏览器厂商也不会再在他们的新版浏览器中更新和升级这一块,取而代之的就是IndexedDBW3C组织鼓励和推崇使用IndexedDB。所以,建议学习人员去看一下IndexedDB的使用方法。

这是相关材料:http://www.html5rocks.com/en/tutorials/webdatabase/websql-indexeddb/

本文的源码:CRX_Mail_WebDataBase


转自:http://www.cnblogs.com/wzh2010/archive/2012/05/22/2514017.html

相关问答

更多
  • 我最近做了一个应用程序需要这个,目标是相同的操作系统。 您可以使用2个数据库的组合: 1. LocalStorage :: 检查localStorage function supports_html5_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } } 将项目设置为LocalStorage loc ...
  • 您好, 我的建议是,如果你想增加自己的入选机会,那最好还是花点钱制作一份专业的简历。相较于你将来可能得到的巨大收获,这真的只是一个小小的投资。 2.研究面试官 当我联系程序员来面试的时候,我总是会事先发电子邮件给他,并附上我的名字和博客地址。但是让我惊讶的是,当我给他面试的时候,他竟然对我还是一无所知。 再举个正面的例子,我在面试时也碰到过这类开发人员,甚至能对我以前写的一篇博客或者做的教学视频上面的内容侃侃而谈。 你说我会推荐哪个? 面试官也是人,也会有人性的弱点和特点。Dale Carnegie曾说过, ...
  • 在HTML5中有几种脱机存储的可能性:Web存储Web SQL数据库IndexedDB文件系统API 这里有所有这些选项的非常好的介绍: http://www.html5rocks.com/en/tutorials/offline/whats-offline/#toc-older-storage 与较早的选项(Cookie,基于插件的存储,浏览器特定功能)相比,我将引用以下文章: “新开发的存储API,我们称之为”HTML5存储“,在开放性和标准合规性方面一般都很优秀,当然,并非所有的浏览器都包含所有新的A ...
  • 馊主意。 访问机器的人总是能够读取本地存储器,没有什么可以做的,以防止它。 只需在firebug控制台中键入“localStorage”,就可以很好地列出所有的键/值对。 如果您的应用程序中存在XSS漏洞,那么存储在localStorage任何内容都可用于攻击者。 你可以尝试加密它,但是有一个catch。 在客户端上加密它是可能的,但这意味着用户必须提供密码, 并且必须依赖于经过验证的未经验证的加密技术的JavaScript实现。 当然可以在服务器端进行加密,但客户端代码无法读取或更新它,因此您将local ...
  • (简单方法)我使用csv格式将数据从vfp DB迁移到mysql。 首先,我在vfp中创建了一个使用表并转换为csv文件的简单应用程序。 然后我通过PHP在服务器上上传该文件,并使用其功能从csv中提取数据并插入到mysql数据库中。 (还需要一些代码)正如你们所讨论的那样,我直接通过mysql odbc连接器从vfp与mysql进行通信,如果你使用带有vfp的sql server只是一些日期格式必须改变,那就不那么困难了。 我的代码如下(创建数据库) LPARAMETERS par_table, par_ ...
  • 你不能使用WebSQL吗? (请参阅问题iPad上的iOS(Safari)中Web SQL DB的最大大小是多少?LocalStorage怎么样? )。 如果您为LocalStorage编码它,您可以轻松地使用LocalStorage API访问iOS设备上的WebSQL ... 也许跳到PhoneGap会解决你的一些问题? 您是否需要存储数据库中的所有数据? 我有一个用于进行Syncrhonization的库,它目前是LocalStorage,但下一次更新将允许我使用几乎任何存储机制,因为它只需要一个索引 ...
  • 仅适合路过的人,不是优雅的解决方案,而是至少一个。 您可以将Adobe动画保存为动画视频('mov'文件),并使用Adobe Media Converter或您喜欢的任何其他程序优化其大小和格式。 在这种情况下我用mp4转换它。 注意:发布视频时,如果有音轨,只有从动画的第二帧开始,它才会包含在视频中。 发现它有点棘手,值得一提。 只要你有一个'mp4'文件,就把它添加到你的应用资产中,你可以用经典的html方式将它包含在Ionic页面中。 就我而言,这是一个全屏播放的视频,所以这是我的代码:
  • Chrome和Safari都有数据库GUI和命令行界面。 正如您所发现的,它们位于Developer Tools的“Resources> Databases”选项卡下(在Safari中称为Web Inspector)。 两者都非常相似,因为两种浏览器都基于Webkit。 您可以通过选择数据库的名称来获取临时查询的命令行界面。 在能够查看数据库之前,您必须在控制台或代码中调用openDatabase() 。 该数据库基于SQLite,因此您可以使用SQLite在此接受的几乎所有命令,除了帮助程序命令,例如'. ...
  • 通过搜索任何HTML文档,我无法找到任何关于硬大小限制或任何大小限制的指示。 我相信Safari在iPhone / iPad的应用程序存储上有5MB的上限( 你曾经提到使用iPad。 ) 这是关于脱机Web应用程序/缓存的HTML标准 这是一个很好的链接,涉及使用HTML5实现离线缓存 - 它还有几个良好的链接到底部。 希望这可以帮助你! I haven't been able to find anything regarding a hard size limitation or any indicati ...
  • 不,jQuery不是必需的。 毕竟,简单地说HTML5样板,样板/模板,可以改变。 如果您不需要jQuery,可以通过删除以下两行来删除它: