使用HTML5 WebDataBase设计离线数据库

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

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

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

如今咱们来封装和提取WebSQL公用方法。sql

 

首先,咱们须要拿到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方法体里面, ide

/*--添加数据表--*/
    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);
        })
    }

 

一共包含了三个参数tableName,fileds,callBack,分表表明你要建立的表名,所对应的字段数组,就是把这个表相应的字段用数组保存起来(方法里面还会自动建立一个表名加上“_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,而且再也不维护它的过期的规范,浏览器厂商也不会再在他们的新版浏览器中更新和升级这一块,取而代之的就是IndexedDB,W3C组织鼓励和推崇使用IndexedDB。因此,建议学习人员去看一下IndexedDB的使用方法。

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

本文的源码:CRX_Mail_WebDataBase

相关文章
相关标签/搜索