亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

web 數據庫

之前的章節有討論過 web 中的存儲方式,包括傳統的 cookie 和新的 localstorage,這兩種方式實現了 HTML 中的離線存儲,但是存儲方式比較簡單,在有些復雜的業務場景可能不能滿足條件。本章我們介紹一個計算機中一個重要的學科數據庫,以及它在 HTML5 中的支持。數據庫是一個內容龐大的知識體系,本章只介紹一些簡單的用法以及它在 HTML 中的適用場景。

1. 適用場景

既然適用 localstorage 也可以做簡單的數據存儲,那么為什么還需要適用數據庫呢?假設一個業務場景中將所有用戶信息臨時存儲到瀏覽器中,這些信息包括昵稱、姓名、性別等,現在需要搜索出性別是男的所有用戶。如果使用 localstorage 的話,需要將所有的數據提取出來,一條條遍歷,得出結果。這樣的搜索算法的時間復雜度是 O(n),性能較差。如果使用數據庫存儲的話,只需要給性別列加上索引,然后使用 SQL 搜索,時間復雜度是 O(lgn),性能提升了一個等量級。關系型數據庫的特點是:

  • 數據模型基于關系,結構化存儲,完整性約束;
  • 支持事務,數據一致性;
  • 支持 SQL,可以復雜查詢;

缺點是:

  • SQL 解析會影響性能;
  • 無法適應非結構化存儲;
  • 橫向擴展代價高;
  • 入門門檻較高。

2. Web SQL

Web SQL不是 HTML5 標準中的一部分,它是一個獨立的規范,引入了 SQL 的 api,關于 SQL 的語法可以參考第三方的教程,在此不做解釋。Web SQL 有 3 個函數

2.1 openDatabase

這個函數用于打開一個數據庫,如果數據庫不存在就創建。它有 5 個參數,分別表示:

  • 數據庫名稱;
  • 版本號;
  • 數據庫備注;
  • 初始化數據大??;
  • 創建/打開成功回調函數
/**
     * 創建數據庫 或者此數據庫已經存在 那么就是打開數據庫
     * name: 數據庫名稱
     * version: 版本號
     * displayName: 對數據庫的描述
     * estimatedSize: 設置數據的大小
     * creationCallback: 回調函數(可省略)
     */
    var db = openDatabase("MySql", "1.0", "數據庫描述", 1024 * 1024);

2.2 transaction

這個函數使用事務執行 SQL 語句,它是一個閉包,例如:

dataBase.transaction( function(tx) { 
    tx.executeSql(
    "create table if not exists test (id REAL UNIQUE, name TEXT)", 
    [],
    function(tx,result){ alert('創建test表成功'); }, 
    function(tx, error){ alert('創建test表失敗:' + error.message); 
    });
});

2.3 executeSql

這個方法用于執行 SQL 語句。

tx.executeSql(
"update stu set name = ? where id= ?",
[name, id],
function (tx, result) {
},
function (tx, error) {
alert('更新失敗: ' + error.message);
});
});

3. indexedDB

IndexedDB 是 HTML5 規范里新出現的瀏覽器里內置的數據庫。它提供了類似數據庫風格的數據存儲和使用方式。存儲在 IndexedDB 里的數據是永久保存,不像 cookies 那樣只是臨時的。IndexedDB 里提供了查詢數據的功能,在線和離線模式下都能使用。

3.1 對比 Web SQL

跟 WebSQL 不同的是,IndexedDB 更像是一個 NoSQL 數據庫,而 WebSQL 更像是關系型數據庫。

3.2 判斷瀏覽器是否支持


window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
if(!window.indexedDB){
    console.log("你的瀏覽器不支持IndexedDB");
}

3.3 創建庫

使用 open 方法創建數據庫。

 var request = window.indexedDB.open("testDB", 2);//第一個參數是數據庫的名稱,第二個參數是數據庫的版本號。版本號可以在升級數據庫時用來調整數據庫結構和數據
 request.onsuccess = function(event){
    console.log("成功打開DB");
 }//成功之后的回調函數

3.4 添加數據

var transaction = db.transaction(["students"],"readwrite");//先創建事務,具有讀寫權限
transaction.oncomplete = function(event) {
    console.log("Success");
};
transaction.onerror = function(event) {
    console.log("Error");
};  
var test = transaction.objectStore("test");
test.add({rollNo: rollNo, name: name});//添加數據

3.5 查詢

var request = db.transaction(["test"],"readwrite").objectStore("test").get(rollNo);//創建具備讀寫功能的事務
request.onsuccess = function(event){
    console.log("結果 : "+request.result.name);    
};//成功查詢的回調函數

3.6 修改


var transaction = db.transaction(["test"],"readwrite");//創建事務
var objectStore = transaction.objectStore("test");
var request = objectStore.get(rollNo);
request.onsuccess = function(event){
    console.log("Updating : "+request.result.name + " to " + name);
    request.result.name = name;//修改數據
    objectStore.put(request.result);//執行修改
};

3.7 刪除

//創建事務,并刪除數據
db.transaction(["students"],"readwrite").objectStore("students").delete(rollNo);

4. 實際項目應用

實例演示
預覽 復制
復制成功!
<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
        <title>離線記事本</title>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
        <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script><!-- 引用jQuery插件 -->
    </head>
    <script>
var datatable = null;
var db = openDatabase("note", "", "notebook", 1024 * 100);
//初始化函數方法
function init() {
    datatable = document.getElementById("datatable");
    showAllData();
}
function removeAllData() {
    for(var i = datatable.childNodes.length - 1; i >= 0; i--) {
        datatable.removeChild(datatable.childNodes[i]);
    }
    var tr = document.createElement("tr");
    var th1 = document.createElement("th");
    var th2 = document.createElement("th");
    var th3 = document.createElement("th");
    th1.innerHTML = "標題";
    th2.innerHTML = "內容";
    th3.innerHTML = "時間";
    tr.appendChild(th1);
    tr.appendChild(th2);
    tr.appendChild(th3);
    datatable.appendChild(tr);
}
//顯示數據庫中的數據
function showData(row) {
    var tr = document.createElement("tr");
    var td1 = document.createElement("td");
    td1.innerHTML = row.title;
    var td2 = document.createElement("td");
    td2.innerHTML = row.content;
    var td3 = document.createElement("td");
    var t = new Date();
    t.setTime(row.time);
    td3.innerHTML = t.toLocaleDateString() + " " + t.toLocaleTimeString();
    tr.appendChild(td1);
    tr.appendChild(td2);
    tr.appendChild(td3);
    datatable.appendChild(tr);
}
//顯示所有的數據
function showAllData() {
    db.transaction(function(tx) {
        tx.executeSql("CREATE TABLE IF NOT EXISTS item(title TEXT,content TEXT,time INTEGER)", []);
        tx.executeSql("SELECT * FROM item", [], function(tx, rs) {
            removeAllData();
            for(var i = 0; i < rs.rows.length; i++) {
                showData(rs.rows.item(i))
            }
        })
    })
}
//添加一條記事本數據
function addData(title, content, time) {
    db.transaction(function(tx) {
        tx.executeSql("INSERT INTO item VALUES (?,?,?)", [title, content, time], function(tx, rs) {
                alert("保存成功!");
            },
            function(tx, error) {
                alert(error.source + "::" + error.message);
            }
    )
    })
}
//點擊保存按鈕
function saveData() {
    var title = document.getElementById("name").value;
    var content = document.getElementById("memo").value;
    var time = new Date().getTime();
    addData(title, content, time);
    showAllData();
}
    
    </script>
    <body onload="init()">
        <div data-role="page" id="pageone">
            <div data-role="header" data-position="fixed">
                <h1>離線記事本</h1>
            </div>
            <div data-role="main" class="ui-content">
                <p align="center">記事</p>
                <table data-role="table" class="ui-responsive">
                    <thead>
                        <tr>
                            <th>標題:</th>
                            <th>內容:</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td><input type="text" id="name"></td>
                            <td><input type="text" id="memo"></td>
                        </tr>
                    </tbody>
                </table>
                <button type="submit" onclick="saveData()">保存</button>
                <table data-role="table" data-mode="" class="ui-responsive" id="datatable">
                </table>
            </div>

        </div>
    </body>
</html>
運行案例 點擊 "運行案例" 可查看在線運行效果

上述代碼通過使用 websql 實現了一個簡單的離線記事本的功能,數據庫中保留 3 個字段,分別是標題、內容、時間,點擊保存按鈕調用insert 豫劇將數據添加到數據庫,然后通過使用 select語句將數據庫中的數據展示出來。如果瀏覽器不主動清空數據的情況下離線數據將會永久保存,這樣的話借助 websql 可以實現與桌面應用相差無幾的功能。

5. indexedDB 和 websql 對比

  • 訪問限制: indexdb 和 websql 一致,均是在創建數據庫的域名下才能訪問,且不能指定訪問域名。

  • 存儲時間: 這兩位的存儲時間也是永久,除非用戶清除瀏覽器數據,可以用作長效的存儲。

  • 大小限制: 理論上講,這兩種存儲的方式是沒有大小限制的。然而 indexeddb 的數據庫超過50M的時候瀏覽器會彈出確認,基本上也相當于沒有限制了。但是由于不同的瀏覽器的實現有一定的差別,實際使用中需要根據不同的瀏覽器做相應的容量判斷容錯。

  • 性能測試: indexeddb 查詢少量數據花費差不多 20MS 左右。大量數據的情況下,相對耗時會變長一些,但是也就在 30MS 左右,也是相當給力了,10W 數據+,畢竟 nosql。而 websql 的效率也不錯,10w+ 數據,簡單查詢一下,只花費了20MS左右。

  • 標準規范: Web SQL 數據庫是一個獨立的規范,因為安全性能等問題,官方現在也已經放棄了維護;indexedDB 則屬于 W3C 標準。

6. 小結

回顧本章,由關系數據庫的優缺點及適用場景引申到 HTML5 中的數據庫解決方案,以及使用方法,需要注意的是在使用 HTML 數據庫的過程中需要檢測瀏覽器是否支持數據庫。實際開發項目由于考慮前端數據庫的安全性以及性能等問題,如果切實需要使用需要謹慎,畢竟一般項目中數據庫保存的都是敏感數據,即使保存在服務器中也需要一定的安全加密措施,所以一般前端存儲的都是一些臨時的數據。