基於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