Web前端开发学习之路——数据的保存与读取(二)

认识Web SQL

Web SQL Database 是关系型数据库系统,使用SQLite语法访问数据库。对于以SQL为基础的关系型数据库的用户而言,学习Web SQ可以说是相当轻松的,因此我在同期更新了一些关于Mysql的文章以便学习。Web SQL Database几乎支持各大浏览器,不惜担心应用程序无法使用。虽然W3C已宣布将弃用Web SQL,相信短时间内Web SQL仍然是开发WebAPP数据库的主流。

Web SQL基本操作

Web SQL就技术层面来说,仍然可以打开数据库并进行数据的新增、读取、更新与删除等相关操作,与IndexedDB数据库操作程序没有什么不同。

操作IndexedDB数据库有以下几个步骤:

  • 创建数据库;
  • 创建交易(transaction);
  • 执行SQL语法;
  • 取得SQL执行结果

创建数据库

创建数据库时,需要定义数据库的名称、版本、描述以及大小,HTML5 Storage的大小会因设备而已,通常来说Android平台的大小不得超过15MB,而IOS平台不得超过10MB,如果开发时遇到问题,可以适当调小数值。

db = openDatabase(dbName,dbVersion,dbDescription,dbSize);

为了检测是否成功创建数据库,可以检查是否为null,例如:

db = openDatabase("MyDatabase","1.0","first DB",2*1024*1024);
if(!db)
    alert("链接数据库失败");

上述语法用于打开名为MyDatabase的数据库,数据库版本为1.0,描述内容为first DB,大小是2MB。当数据存在时会打开数据库,不存在则创建。

如果版本号码与现有数据库版本号码不相符,会无法打开数据库,建议写空白字符串代表不限版本或者用changeVersion方法来更改数据库版本,更改数据库版本的语法架构如下:

db.changeVersion(oldVersionNumber,newVersionNumber,callback,
errorCallback,successCallback);

例如:

db.changeVersion("","1",function(tx){
    //executeSql
},function(e){
    //失败时执行的语句
},function(){
    //成功时执行的语句
});

创建交易

创建交易时使用database.transaction()函数,其格式如下所示。

transaction(querysql,errorCallback,successCallback);

Querysql是实际执行的函数,通常会定义为匿名函数,可以在函数中执行SQL语法。举例来说:

db.transaction(fcunction(tx){
    //executeSql
},function(e){
    //失败时执行的语句
},function(){
    //成功时执行的语句
});

执行SQL语法

Transaction中的querysql就可以使用SQL进行数据库的操作,创建数据表、新增/修改/删除/查询数据等,使用的就是executeSQL函数,格式如下:

executeSql(sqlStatement,arguments,callback,errorCallback);

各个参数说明如下:

  • sqlStatement :要执行的SQL语法
  • arguments:如果上述sqlStatement使用的SQL语法能够动态变化,可以采用变量的方式,以问号(?)来取代变量,在Arguments中按照问号(?)顺序排列成一串组合,例如:
sqlStatemennt = 'update customer set name= ? where id=?';
Arguments = ['brain','123'];
  • callback:成功时获取计算结果的语句,请参考下面的内容
  • errorCallback:失败时执行的语句

取得SQL执行结果

当SQL查询执行成功后,就可以用循环来取得执行的结果行,如下所示:

for(var i= 0;i<result.rows.length;i++){
    item = result.rows.item(i);
    #("div").html(item["name"]+"<br>");
}

结果行以result.rows表示,使用result.rows.length就能得知数据共几条,每条数据使用result.rows.item(index)就可以得到,index指的时行的索引位置,从0开始,取得单条数据之后就可以指定字段名称,从而得到所需的数据。

创建数据表

大多数浏览器使用的SQL后台都是SQLite,SQLite时一个轻型嵌入式关系型数据库(embedded SQL database),它值是一个文件,不要特别的设置,没有服务器和配置文件,对移动设备来说时非常好用的数据库,然而它本身并不是标准语言,也没有完全遵守SQL标准,所以有写SQL语法是无法使用的。下面进入SQLite语法的操作,先来看看创建数据表的语法:

create table tabe_name(
    column1 datatype PRIMARY KEY,
    column2 datatype,
    ...
);

table_name是数据表的名称,column是字段的名称,datatype是数据类型,PRIMARY KEY是主键,表示字段中的数据必须是唯一值,不能重复,AUTOINCREMENT是自动编号,举例如下:

CREATE TABLE customer(
    id int PRIMARY KEY,
    name char(10),
    address varchar(200)
);

上述语句创建了3个字段,分别是id、name和address,其中id字段是主键,不允许重复值,name字段的数据类型是10位的char(固定长度的字符串),address是200位的varchar(可变长度的字符串)。

SQLite并不强制指定数据类型,数据保存时会以最合适的保存类别(Storage Class)进行保存,也就试说就算不写数据类型也可以,如下:

CREATE TABLE customer (id,name,address);

SQLite的保存类别只有5种,但几乎包含了所有的数据类型,如下:

  • text:当声明为char、varchar、nvarchar、text、clob等字符串类型就被会归类为text,如char(10)、vachar(255)
  • numeric:当声明为numeric、decimal(10,50)、boolean、date、datetime时会被归类为numeric
  • integer:当声明为int、integer、tinyint、smallint、mediumint等整数类型时会被归类为integer
  • real:当声明为real、double、float等浮点数(具有小数点的数值)类型时就会被归类为real
  • none:不做任何数据类型操作

当数据表已经存在时,执行create table命令就会出错。我们加上if not exists命令来确保create table命令正常运行,如下:

create table if not exists customer(
    id integer primary key,
    name char(10),
    address varchar(200)
)

下面请看一个范例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SQLite</title>
    <script src="../jquery-3.3.1.min.js"></script>
</head>
<script type="text/javascript">
    $(function () {
        //打开数据库
        var dbSize = 2*1024*1024;
        db = openDatabase('firstDB','','',dbSize);
        //创建数据表
        db.transaction(function (tx) {
            tx.executeSql("CREATE TABLE IF NOT EXISTS customer(id integer PRIMARY KEY,name char(10),address varchar(200))",[],onSuccess,onError);
        });
        function onSuccess(tx,results) {
            $("div").html("打开数据库成功!")
        }
        function onError(e) {
            $("div").html("打开数据错误:"+e.message)
        }
    })
</script>
<body>
    <div id="message"></div>
</body>
</html>

执行后会发现Web SQL新增了customer数据表:

Web前端开发学习之路——数据的保存与读取(二)

新增、修改和删除数据

新增数据的语法如下:

INSERT INTO tableName(column1,column2,...) VALUES (value1,value2,...)

例如:

INSERT INTO customer(name,address)VALUES('brian','上海市');

SQL语法中的字符串前后只能使用单引号。

如果字段被设置为PRIMARY KEY,当INSERT时没有命令字段值,会直接从字段的最大值加1,相当于设置了AUTOINCREMENT自动编号。

修改数据

修改数据使用的时UPDATE命令,语法如下:

UPDATE tableName SET column1 = value1,colum2 = value2,...WHERE condition;

condition是指要更新的条件,例如,要将id为1的姓名修改成为Jennifer,就可以使用下式表示:

UPDATE customer SET name ='Jennifer' WHERE id =1;

如果要将资料表的某个字段一次更新,只要省略WHERE子句即可,例如要将地址全部改为上海市,就可以使用下式表示:

UPDATE customer SET address ='上海市';

删除数据

删除数据使用的是DELETE命令语法如下:

DELETE FROM tableName WHERE condition;

SQL语法相当容易理解和记忆,DELETE语法就是从某数据表(FROM)中找出符合的数据(WHERE)并删除(DELETE)。举例来说,从customer数据表中删除name为Jennifer的数据,语法如下:

DELETE FROM customer WHERE name ='Jennifer';

WHERE子句指定要删除哪一条数据,如果省略WHERE子句,所有数据都会被删除。

读取数据

要取出数据使用的是SELECT命令,语法如下:

SELECT column1,column2 FROM tableName WHERE condition;

例如:

SELECT id,address FROM customer WHERE name='Jennifer';

找到数据之后可以使用循环来获取,结果以result.rows表示,用result.rows.length就能得知数据共有几条,每条数据使用result.rows.item(index)就可以获取,index指的行的索引位置,从0开始,取得单行数据之后再指定字段名称,就可以取得所需的数据了,如下所示:

for(var i=o;i<result.rows.length;i++){
    item = result.rows.item(i);
    $("div").html(item["name"]+"<br>");
}

现在就来看看完整的数据库创建和数据新增、删除的范例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SQLite</title>
    <script src="../jquery-3.3.1.min.js"></script>
    <style>
        table{
            border-collapse: collapse;
        }
        td{
            border:1px solid #0000cc;
            padding: 5px;
        }
        #message{
            color:#ff0000
        }
    </style>
    <script type="text/javascript">
        $(function () {
            //打开数据库
            var dbSize = 2*1024*1024;
            db = openDatabase('firstDB','','',dbSize);
            db.transaction(function (tx) {
                //创建数据表
                tx.executeSql("CREATE TABLE IF NOT EXISTS customer(id integer PRIMARY KEY ,name char(10),address varchar(200))");
                showAll();
            });

            $("button").click(function () {
                var name =$("#name").val();
                var address =$("#address").val();
                if(name==""||address==""){
                    $("#message").html("**请输入姓名和地址**");
                    return false;
                }
                db.transaction(function (tx) {
                    //新增数据
                    tx.executeSql("INSERT INTO customer(name,address)VALUES (?,?)",[name,address],function (tx,result) {
                        $("#message").html("新增数据完成!")
                        showAll();
                    },function (e) {
                        $("#message").html("新增数据错误:"+e.message)
                    });
                });
            })
            $(document).on('click',".delItem",function () {
                var delid = $(this).prop("id");
                db.transaction(function (tx) {
                    //删除数据
                    var delstr ="DELETE FROM customer WHERE id =?";
                    alert(delstr)
                    tx.executeSql(delstr,[delid],function (tx,result) {
                        $("#message").html("删除数据完成!")
                        showAll();
                    },function (e) {
                    $("#message").html("删除数据错误:"+e.errorCode);
                });
            });
        })
        function showAll() {
            $("#showData").html("");
            db.transaction(function (tx) {
                //显示customer数据表全部数据
                tx.executeSql("SELECT id,name,address FROM customer",[],function (tx,result) {
                if(result.rows.length>0){
                    var str ="现有数据:<br><table><tr><td>id</td><td>姓名</id><td>地址</id><td>&nbsp;</id></tr>;"
                    for(var i =0;i<result.rows.length;i++){
                        item = result.rows.item(i);
                        str +="<tr><td>"+item["id"] + "</td><td>" +item["name"] + "</td><td>" + item["address"] + "</td><td><input type='button' id='"+item["id"]+"'class='delItem' value='删除'></td></tr>";
                    }
                    str+="</table>";
                    $("#showData").html(str);
                }
                });
            },function (e) {
                $("#message").html("SELECT语法出错了!"+e.message)
            });
        }
})
    </script>
</head>
<body>
<!--新增-->
<table>
    <tr>
        <td>姓名:</td>
        <td><input type="text" id="name"></td>
    </tr>
    <tr>
        <td>地址:</td>
        <td><input type="text" id="address"></td>
    </tr>
</table>
<button id = 'new'>发送</button>
<p>
    <div id="message"></div>
    <div id="showData"></div>
</p>
</body>
</html>

上述代码又是敲代码几分钟,找bug一小时,由于原书中就已经出现bug,在我的仔细观察下还是给它找出来了!执行结果如下:

Web前端开发学习之路——数据的保存与读取(二)

用户输入数据单击“发送”按钮就可以新增一条记录,单击“删除”按钮来删除记录。然而“删除”按钮是动态产生的,网页加载时并不存在,就不能采用直接绑定,范例中的“发送”、“删除”按钮绑定事件使用的是jQuery语法。