前端儲存之websql
最近公司系統需要做一個app,經過調查研究,決定用html5 + phonegap技術來開發,一方面對於html5技術已經很熟悉(雖然之前android也有所研究,但是還是在html5方面傾注精力更多),而且公司的專案pc端本身就是B/S的,移植到手機端比較容易,研發成本也比較低;另外基於html5技術的開發,可以做到跨平臺,同時跑在android 和iOS兩大系統沒有問題。
app需要用到一些前端儲存,而且是關係型資料儲存的需求,當然用phonegap的機制,可以呼叫native的儲存,不過實現起來很麻煩;所以就考慮用html5的前端離線儲存,前端離線儲存目前支援 Cookie、localStorage、sessionStorage、IndexedDB、Web SQL Database以及FileSystem.
Cookie就不用說,用起來超級麻煩,而且限制極大;不適合。
sessionStorage其實算不上離線儲存,因為網頁關閉了,儲存就會丟棄。
localStorage可以做key value 的儲存,對於需要有些關係處理的資料,需要自己做邏輯處理,比較麻煩。
IndexedDB其實就是前段的nosql資料庫。
比較靠譜的是websql和IndexedDB,不過由於需要關係資料庫的原因,選擇了websql,不過IndexedDB也是一個不錯的選擇,後面有機會寫寫這塊。
需要注意的是,HTML5已經會放棄Web SQL Database
放棄的原因如下:
This document was on the W3C Recommendation track but specification work has stopped. The specification reached an impasse: all interested implementors have used the same SQL backend (Sqlite), but we need multiple independent implementations to proceed along a standardisation path.
大概意思是:
該檔案是W3C推薦標準,但規範的制定工作已經停止。該規範陷入僵局:所有感興趣的實現者都使用了相同的SQL後端(SQLite的),但我們需要多個獨立的實現沿著規範化的路徑進行。
翻譯參考:http://www.zhihu.com/question/41951041
有關標準參考: https://www.w3.org/TR/webdatabase/
關於這一點,我覺得一方面我們的app是驗證型的,並不是正式需要釋出的,所以選擇websql沒有什麼後顧之憂,另外,我覺得,瀏覽器廠商就算以後不再改進websql,把現有的websql功能去掉的可能性不是很大,而目前的功能也滿足需求了。
websql是很久的技術了,很早關注過,不過一直沒用,最近想用,搜尋了下,網上關於websql的文章已經很多,但是發現大部分文章都是抄來抄去的;可能很多東西大家也沒有試驗,就抄襲了過來;正好自己用到了相關的知識,就來個比較全面的整理。
如果你掌握過mysql,orancle,mssql等關係型資料庫,對於websql的理解還是比較容易的。
websql的關鍵技術點分為:
- 測試瀏覽器支援
- 建立資料庫
- 建立表格
插入資料等
用到的幾個核心方法:
openDatabase openDatabaseSycn 建立資料庫
- transaction起事務
- executeSql執行sql語句
測試瀏覽器支援
if(window.openDatabase){
console.log(“瀏覽器支援DataBase”);
}
建立資料庫
在window物件上,有一個openDatabase方法,可以建立資料庫,參考標準
Database openDatabase(in DOMString name, in DOMString version, in DOMString displayName, in unsigned long estimatedSize, in optional DatabaseCallback creationCallback);
var test_db = window.openDatabase('test', '1.0', 'Test DB', 2 * 1024 * 1024);
openDatabase共四個引數,第一個引數資料庫名,第二個引數資料庫版本號,第三個描述,第四個估計大小,四個引數都必須輸入,但是最後一個引數可以輸入null,最終建立的物件如下:
可以看出db物件上面有changeVersion方法可以改變版本號,.version可以獲取版本號,transaction方法可以起事務,readTransaction方法起一個只讀的事務,參考標準
For the transaction() method, the mode must be read/write. For the readTransaction() method, the mode must be read-only.
其實標準裡面還有個openDatabaseSync方法,但是測試發現並沒有實現【測試chrome,safari】
openDatabase還有第5個引數creationCallback,可選擇的;但是測試發現如果加入了callback引數,建立的database的版本號就總是為空。
起資料庫事務
從前面的圖片中可以看到,有兩個事務的方法,一個transaction,一個readTransaction, 兩個方法均是非同步的,通過傳遞一個callback來執行後續操作
test_db.transaction(function(tx){console.log(tx);})
回撥函式會被傳入一個SQLTransaction物件,該物件可以執行executeSql方法。
執行SQL語句
執行sql語句和一般的關係型資料庫類似,不同的是,websql支援的資料型別 函式 等都相當有限。
executeSql支援四個引數,sql語句,sql引數,成功回撥函式,錯誤回撥函式,回撥函式第一個引數是transaction,第二個是執行結果;錯誤回撥函式第一個引數是transaction,第二個引數是錯誤。
建立一個數據表
var success = function(tx,results){
console.log(results);
};
var error = function(tx, err){
console.log(error);
};
var sql = 'CREATE TABLE foo (id unique, text)';
test_db.transaction(function(tx){
tx.executeSql(sql,[],success,error);
});
可以看出不需要指定欄位的型別,unique表示唯一,其實也可以指定型別,但是測試發現其實指定了也沒什麼用,如下指定todo型別為TEXT,added_on 為DATETIME,但是在後面可以插入任意型別資料,不起約束左右;另外看有的文章說不支援自增長,測試發現是可以的。【只是在pc上測試了chrome和safari,未測試移動端的情況】【後來在移動端測試也可以】
tx.executeSql("CREATE TABLE IF NOT EXISTS " +
"todo(ID INTEGER PRIMARY KEY ASC, todo TEXT, added_on DATETIME)", [],success,error);
插入資料
test_db.transaction(function(tx){
tx.executeSql('INSERT INTO foo (id, text) VALUES (1, "test")',[],success,error);
});
查詢資料
tx.executeSql('SELECT * FROM foo', [], function (tx, results) {
var len = results.rows.length, i;
for (i = 0; i < len; i++) {
alert(results.rows.item(i).text);
}
});
查詢的資料格式標準如下,通過rows.item()可以訪問資料
interface SQLResultSet {
readonly attribute long insertId;
readonly attribute long rowsAffected;
readonly attribute SQLResultSetRowList rows;
};
參考: https://www.w3.org/TR/webdatabase/#sqlresultset
刪除資料
test_db.transaction(function(tx){
tx.executeSql("DELETE FROM todo foo ID=?", [id],success,error);
});
支援瀏覽器情況
firefox 不支援,IE edge 一貫作風不支援; chrome Safari支援,移動端android iOS支援的都很不錯,
具體參考 http://caniuse.com/#feat=sql-storage
使用場景
有本地儲存需求的應用,比如開發一個本地儲存的web端遊戲;
如果開發基於html5技術的手機app,也可以考慮用websql做本地儲存,不過由於前面提到的原因,如果你的app考慮長遠發展,建議使用IndexedDB。