|
基于HTML5的Web DataBase 可以讓你在瀏覽器中進(jìn)行數(shù)據(jù)持久地存儲管理和有效查詢,假設(shè)你的離線應(yīng)用程序有需要規(guī)范化的存儲功能,那么使用Web DataBase,可以使你的應(yīng)用程序無論是在離線或者在線或者網(wǎng)絡(luò)不通暢情況下都可以將數(shù)據(jù)保存在客戶端。 下面是HTML5 DataBase中兩個不同的DataBase的比較,摘自http://www./en 上面的一篇文章。
我們這邊使用WebSQL來設(shè)計(jì)和編寫底層服務(wù),W3C 的 WebDatabase 規(guī)范中說這份規(guī)范不再維護(hù)了,但是幾乎實(shí)現(xiàn)者都選擇了SQLite這種輕量簡單易用的客戶端數(shù)據(jù)庫: 現(xiàn)在我們來封裝和提取WebSQL公用方法。
首先,我們需要拿到SQLite數(shù)據(jù)庫可操作和執(zhí)行的SQL數(shù)據(jù)上下文: 這邊通過openDatatBase方法打開或創(chuàng)建數(shù)據(jù)庫: ![]() 1 /*-------執(zhí)行SQLite注入,數(shù)據(jù)庫的基本操作(Begin)-------*/ 2 function SQLProvider(dbName, size) { 3 this.dbName = dbName || 'OFLMAIL'; 4 5 var db = openDatabase(this.dbName, '1.0', 'database for ' + this.dbName, (size || 2) * 1024 * 1024); 6 this.db = db; 7 8 /*-------執(zhí)行SQLite注入,數(shù)據(jù)庫的基本操作(End)-------*/ 9 10 function sqlerrorHandler(tx, e) { 11 log.error(e.message); 12 } 這邊還可以設(shè)置數(shù)據(jù)庫的名稱dbName和數(shù)據(jù)庫大小size,默認(rèn)數(shù)據(jù)庫名稱是OFLMAIL,就是我們這個離線系統(tǒng)的名稱,默認(rèn)大小是2兆。 我們還可以設(shè)置錯誤處理方法sqlErrorHandler,用戶處理操作失敗之后的錯誤捕捉 這樣,我們就拿到了操作SQLite的數(shù)據(jù)上下文db,通過上下文db,我們可以執(zhí)行相應(yīng)的CURD操作。
第一步,我們寫一個創(chuàng)建數(shù)據(jù)表的方法,把這個方法放在SQLProvider方法體里面, ![]() 1 /*--添加數(shù)據(jù)表--*/ 2 this.createTable = function (tableName, fields, callBack) { 3 var pkField = tableName + "_SEC"; 4 var sql = "CREATE TABLE IF NOT EXISTS " + tableName + "( " + pkField + " integer primary key autoincrement,"; 5 6 // 合并字段串同時去除傳入的主鍵字段 7 sql += fields.join(",").replace(pkField + ",", "") + ")"; 8 //log.debug(sql); 9 10 db.transaction(function (tx) { 11 tx.executeSql(sql, [], function () { 12 if (callBack) callBack(); 13 }, sqlerrorHandler); 14 }) 15 } 一共包含了三個參數(shù)tableName,fileds,callBack,分表代表你要創(chuàng)建的表名,所對應(yīng)的字段數(shù)組,就是把這個表相應(yīng)的字段用數(shù)組保存起來(方法里面還會自動創(chuàng)建一個表名加上“_SEC”的字段,他是個增量標(biāo)識,用做主鍵),callBack顧名思義,回調(diào)函數(shù),這個參數(shù)可以不傳。這個回調(diào)函數(shù)的存在很重要,因?yàn)檎麄€基于SQLite數(shù)據(jù)庫的操作方法都是異步調(diào)用的,所以需要在回調(diào)函數(shù)中嵌套執(zhí)行,否則有些執(zhí)行會被中斷。
將這個函數(shù)放在SQLProvider里面,有一個好處就是到時候可以在SQLProvider的動態(tài)實(shí)例化中直接調(diào)用該函數(shù) 如:var sqlProvider = new SQLProvider(); sqlProvider.createTable(“UserInfo”,new Array(“UserName”,”UserPwd”)); 這樣子,方便我們在頁面中調(diào)用。這種操作方法相當(dāng)于C#里面的動態(tài)類創(chuàng)建方法,SQLProvider就是類名,createTable就是類中的方法,實(shí)例化調(diào)用。
接下來我們的數(shù)據(jù)庫的操作,包括數(shù)據(jù)表和數(shù)據(jù)的CURD操作,都會以這種方法寫在里面: 刪除數(shù)據(jù)表(只需傳入表名就行了,他會刪除相應(yīng)的數(shù)據(jù)表): ![]() 1 /*--刪除數(shù)據(jù)表--*/ 2 this.dropTable = function (tableName) { 3 var sql = "DROP TABLE " + tableName; 4 db.transaction(function (tx) { 5 tx.executeSql(sql); 6 }) 7 }
添加數(shù)據(jù)(包含了四個參數(shù):表名,字段數(shù)組,字段所對應(yīng)的值的數(shù)組,和一個回調(diào)函數(shù)) 這邊的fields和values代表了字段數(shù)組和值數(shù)組,他們一一對應(yīng): 如 var fileds=new Array(“UserName”,”UserPwd”); var values=new Array(“Ben”,”123456”);則說明在UserInfo表里面添加了一條數(shù)據(jù),這條數(shù)據(jù)至少包含三個有值的字段,主鍵,UserName和UserPwd,而values 則是相應(yīng)的值數(shù)組。 回調(diào)函數(shù)中帶有一個返回的參數(shù),返回了你所添加的改行數(shù)據(jù)的主鍵。 ![]() 1 /*--添加數(shù)據(jù)(插入數(shù)據(jù))--*/ 2 this.insertRow = function (tableName, fields, values, callback) { 3 var sql = "INSERT INTO " + tableName + " (" + fields.join(",") + ") SELECT " 4 + new Array(values.length + 1).join(",?").substr(1); 5 6 db.transaction(function (tx) { 7 tx.executeSql(sql, values, function () { }, sqlerrorHandler); 8 //log.debug(sql); 9 10 tx.executeSql("SELECT max(" + tableName + "_SEC) id from " + tableName, [], function (tx, result) { 11 var item = result.rows.item(0); 12 var id = parseInt(item.id); 13 //log.debug("id=" + id); 14 if (callback) callback(id); 15 }, sqlerrorHandler); 16 }); 17 }
刪除數(shù)據(jù) (包含了三個參數(shù):表名tableName,主鍵sec和一個回調(diào)函數(shù)callback) 這個主鍵SEC是該待刪除的數(shù)據(jù)在Web DataBase中的主鍵,我們前面在建表的時候有一個增量標(biāo)識字段,該字段的名稱為表名加上“_SEC”,因?yàn)槲ㄒ恍?所以我們可以根據(jù)這個主鍵來刪除該行數(shù)據(jù), 代碼如下: ![]() 1 /*--刪除數(shù)據(jù)--*/ 2 this.deleteRow = function (tableName, sec,callback) { 3 var pkField = tableName + "_SEC"; 4 var sql = "DELETE FROM " + tableName + " WHERE " + pkField + " = ?"; 5 db.transaction(function (tx) { 6 tx.executeSql(sql, [sec], null, sqlerrorHandler); 7 if (callback) callback(); //使用回調(diào) 8 }) 9 }
修改數(shù)據(jù)(這邊包括了四個參數(shù),表名tableName,字段數(shù)組fields,值數(shù)組values,回調(diào)函數(shù)callback) 字段數(shù)組和值數(shù)組必須是一一對應(yīng)的,而且第一個字段必須是主鍵,所對應(yīng)的values的第一個值也必須是主鍵的值,這樣,可以根據(jù)字段的主鍵來查詢相應(yīng)的數(shù)據(jù)行。 查出的數(shù)據(jù)行之后,可以根據(jù)后面的相應(yīng)字段,進(jìn)行修改。 ![]() 1 /*--更新列,這邊需要注意的是兩個參數(shù)列表的首位必須是主鍵(或者說第一個必須是條件,后面的是修改位)--*/ 2 this.updateRow = function (tableName, fields, values,callback) { 3 var len = fields.length; 4 5 var sql = ""; 6 for (i = 1; i < len; i++) { 7 if (i == 1) sql += fields[i] + " = '" + values[i] + "'"; 8 else sql += "," + fields[i] + " = '" + values[i] + "'"; 9 } 10 11 sql = 'UPDATE ' + tableName + ' SET ' + sql + ' where ' + fields[0] + '= ?'; 12 //log.debug("sql:" + sql); 13 14 db.transaction(function (tx) { 15 tx.executeSql(sql, [values[0]], 16 null, sqlerrorHandler); 17 //log.debug("update " + tableName + " success! sec=" + values[0]); 18 if (callback) callback(); 19 }); 20 } 21 } 調(diào)用方式類似如下: 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的數(shù)據(jù)行,修改它的UserName的值為:“Ben”, 修改它的UserPwd的值為:“123456”
根據(jù)主鍵查詢單行數(shù)據(jù)(包含三個參數(shù)表名tableName,主鍵SEC,回調(diào)函數(shù)callback): 根據(jù)表名和主鍵名稱獲取到該行數(shù)據(jù),并返回,注意到這邊通過cllback回調(diào)函數(shù)來返回查詢的結(jié)果,通過數(shù)據(jù)上下文tx執(zhí)行該SQL腳本,返回的是結(jié)果集result,這邊我們?nèi)∷Y(jié)果集的第一條數(shù)據(jù)也即是result.rows.item(0),實(shí)際上結(jié)果集中也只有一條數(shù)據(jù)。 ![]() 1 /*--讀取單行數(shù)據(jù)--*/ 2 this.readRow = function (tableName, sec, callback) { 3 db.transaction(function (tx) { 4 tx.executeSql('SELECT * FROM ' + tableName + ' WHERE ' + tableName + '_SEC = ?', [sec], function (tx, result) { 5 if (callback) callback(result.rows.item(0)); // 使用回調(diào) 6 }, sqlerrorHandler); 7 }); 8 }
讀取指定的數(shù)據(jù)表(根據(jù)表名來讀取相應(yīng)的數(shù)據(jù)表,并返回結(jié)果集): ![]() 1 /*--讀取數(shù)據(jù)表--*/ 2 this.loadTable = function (tableName, callback) { 3 db.transaction(function (tx) { 4 tx.executeSql('SELECT * from ' + tableName, [], function (tx, result) { 5 if (callback) callback(result); //使用回調(diào) 6 }, sqlerrorHandler); 7 }); 8 } 結(jié)果集result中的列的集合用result.rows表示 列的數(shù)量用result.rows.length來表示 單條數(shù)據(jù)是用result.rows.item(index)表示,index指的是列的索引位置,從0開始
根據(jù)SQL的where條件語句來讀取指定的數(shù)據(jù)表(根據(jù)表名tableName和sqlSenten條件語句來執(zhí)行,并返回結(jié)果集): ![]() 1 /*--根據(jù)查詢條件讀取數(shù)據(jù)表--*/ 2 this.loadTableBySQl = function (tableName, sqlSenten, callback) { 3 db.transaction(function (tx) { 4 tx.executeSql('SELECT * from ' + tableName+" WHERE "+ sqlSenten, [], function (tx, result) { 5 if (callback) callback(result); //使用回調(diào) 6 }, sqlerrorHandler); 7 }); 8 } 與上面的方法類似,只是多了一個sqlSenten條件語句來篩選數(shù)據(jù)
根據(jù)某個字段檢查是否存在該列(通過字段名和字段所對應(yīng)的值)來進(jìn)行操作,過多地用于根據(jù)主鍵來查詢數(shù)據(jù)行: ![]() 1 /*--檢查是否已存在該列--*/ 2 this.checkExist = function (tableName, fieldName, fieldValue, callback) { 3 db.transaction(function (tx) { 4 tx.executeSql('SELECT * from ' + tableName + ' where ' + fieldName + '= ?', [fieldValue], function (tx, result) { 5 var isExist; 6 if (result.rows.length == 1) isExist = "1"; else isExist = "0"; //1代表存在該行,0 代表不存在該行 7 if (callback) callback(isExist); 8 }, sqlerrorHandler); 9 }); 10 } 當(dāng)檢索讀到的結(jié)果集合中包含了一條數(shù)據(jù)的時候,返回1,代表存在該行,為0的時候代表不存在該行。這邊做的其實(shí)不完善只能在唯一值的字段中才能夠過正確顯示,如主鍵,此外還可以通過where條件語句來驗(yàn)證是否存在該行。這邊就不說了,自己去嘗試。 這樣就完成了整個離線數(shù)據(jù)庫的CURD操作,如果有不夠的地方,我們可以繼續(xù)修改完善,完整代碼如下,在代碼的結(jié)尾我們進(jìn)行了實(shí)例化,我們把這些代碼獨(dú)立地存放到WebDataBase.js文件里面,這樣可以在繼承這個腳本文件的頁面里直接調(diào)用這個腳本庫的方法。
現(xiàn)在我們把這些數(shù)據(jù)庫的的操作應(yīng)用到我們的系統(tǒng)中, 我們的用戶信息頁面(Information.html),用來保存登錄用戶的個人信息的: 包含了如下字段:姓名,性別,入職時間,工號和部門:
在載入的時候查看是否有數(shù)據(jù),有數(shù)據(jù)則顯示第一條 ![]() 1 $(document).ready(function () { 2 sqlProvider.loadTable("UserInfo", function (result) { 3 // result.rows 獲取到所有數(shù)據(jù)行 4 if (result.rows.length > 0) { 5 var row = result.rows.item(0); 6 $("#UserName").val(row.UserName); 7 $("#UserSex").val(row.UserSex); 8 $("#ReportDutyTime").val(row.ReportDutyTime); 9 $("#JobNumber").val(row.JobNumber); 10 $("#DepartmentNumber").val(row.DepartmentNumber); 11 //這邊包含一個隱藏域,可以保存該用戶信息的主鍵 12 $("#UserInfo_SEC").val(row.UserInfo_SEC); 13 } 14 }) 15 }) 我們的保存按鈕的代碼如下: ![]() 1 function onformsumit() 2 { 3 //創(chuàng)建用戶信息表(存在跳過,不存在創(chuàng)建),包含六個字段, 4 //因?yàn)閯?chuàng)建的時候會自動創(chuàng)建一個UserInfo_SEC的主鍵,所以實(shí)際上是6個字段 5 //UserName:用戶名稱 6 //UserSex:用戶性別 7 //ReportDutyTime:入職時間 8 //JobNumber:工號 9 //DepartmentNumber:部門 10 //Remark:備注 11 12 13 var UserName = $("#UserName").val(); 14 var UserSex = $("#UserSex").val(); 15 var ReportDutyTime = $("#ReportDutyTime").val(); 16 var JobNumber = $("#JobNumber").val(); 17 var DepartmentNumber = $("#DepartmentNumber").val(); 18 var Remark = ""; 19 20 var fields = new Array("UserName", "UserSex", "ReportDutyTime", "JobNumber", "DepartmentNumber", "Remark"); 21 var values = new Array(UserName,UserSex,ReportDutyTime,JobNumber,DepartmentNumber,Remark); 22 sqlProvider.createTable("UserInfo", fields, function () { 23 log.debug("創(chuàng)建數(shù)據(jù)表UserInfo"); 24 25 var UserInfo_SEC = $("#UserInfo_SEC").val(); 26 //取隱藏域的值,如果是0則為保存不為0則為修改 27 if (UserInfo_SEC == "0") { 28 sqlProvider.insertRow("UserInfo", fields, values, function () { 29 log.debug("插入數(shù)據(jù)成功!"); 30 alert("保存成功!"); 31 }); 32 } 33 else { 34 sqlProvider.updateRow("UserInfo", fields, values, function () { 35 log.debug("修改數(shù)據(jù)成功!"); 36 alert("保存成功!"); 37 }); 38 } 39 }); 40 return false; 41 } 保存成功之后,數(shù)據(jù)就存儲在我們離線的數(shù)據(jù)庫里面了,載入時顯示在頁面效果如下:
我們?nèi)g覽器中的DataBase中查看,就可以看到這條數(shù)據(jù)了,如圖:
//以下是表單重置函數(shù),刪掉該用戶信息的代碼 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 宣布 將不再關(guān)注Web SQL databas,并且不再維護(hù)它的過時的規(guī)范,瀏覽器廠商也不會再在他們的新版瀏覽器中更新和升級這一塊,取而代之的就是IndexedDB,W3C組織鼓勵和推崇使用IndexedDB。所以,建議學(xué)習(xí)人員去看一下IndexedDB的使用方法。 這是相關(guān)材料:http://www./en/tutorials/webdatabase/websql-indexeddb/ 本文的源碼:CRX_Mail_WebDataBase |
|
|