Web SQL 数据库全面指南与最佳实践(十一)

HTML5 Web SQL 数据库提供了一种在客户端存储数据的方法,尽管该 API 已被废弃,但在某些老旧浏览器中仍有一定的应用场景。本文将详细介绍 Web SQL 的核心方法、基本操作及实际应用示例,并探讨其未来的替代方案——IndexedDB。

Web SQL 的现状与替代方案

Web SQL API 虽然曾经广受欢迎,但由于其未来不确定性和不再有广泛支持,建议开发者转向使用 IndexedDB。IndexedDB 是一种支持事务、键值对存储的现代浏览器 API,更适合现代 Web 应用的需求。

核心方法

Web SQL 提供了几个核心方法,用于数据库的创建、事务管理和 SQL 查询执行:

  1. openDatabase:创建或打开一个数据库对象。
  2. transaction:控制事务的执行,包括提交和回滚。
  3. executeSql:执行实际的 SQL 查询。

打开数据库

使用 openDatabase 方法可以打开已存在的数据库,如果数据库不存在,则会创建一个新的数据库。以下是一个示例:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);

openDatabase 方法的参数说明:

  1. 数据库名称:指定要打开或创建的数据库名称。
  2. 版本号:指定数据库的版本。
  3. 描述文本:对数据库的简短描述。
  4. 数据库大小:指定数据库的最大存储空间。
  5. 创建回调:可选参数,当创建数据库后会被调用。

执行查询操作

使用 transaction 方法可以控制事务的执行,并在事务中执行 SQL 查询。以下是一个创建表的示例:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
});

插入数据

在创建表之后,可以使用 executeSql 方法插入数据。以下是一个插入静态数据的示例:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "菜鸟教程")');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "www.runoob.com")');
});

你也可以使用动态值来插入数据:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (?, ?)', [e_id, e_log]);
});

读取数据

以下示例展示了如何读取数据库中已存在的数据:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "菜鸟教程")');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "www.runoob.com")');
});

db.transaction(function (tx) {
    tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
        var len = results.rows.length;
        var msg = "
<p>查询记录条数: " + len + "</p>";
        document.querySelector('#status').innerHTML += msg;
        for (var i = 0; i < len; i++) {
            alert(results.rows.item(i).log);
        }
    }, null);
});

完整实例

以下是一个完整的示例,展示了如何创建数据库、插入数据、读取数据并显示结果:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
var msg;

db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "菜鸟教程")');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "www.runoob.com")');
    msg = '
<p>数据表已创建,且插入了两条数据。</p>';
    document.querySelector('#status').innerHTML = msg;
});

db.transaction(function (tx) {
    tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {

        var len = results.rows.length;
        var msg = "
<p>查询记录条数: " + len + "</p>";
        document.querySelector('#status').innerHTML += msg;
        for (var i = 0; i < len; i++) {
            msg = "
<p><b>" + results.rows.item(i).log + "</b></p>";
            document.querySelector('#status').innerHTML += msg;
        }
    }, null);
});

删除记录

删除记录的格式如下:

db.transaction(function (tx) {
    tx.executeSql('DELETE FROM LOGS WHERE id=1');
});

你也可以使用动态值来删除记录:

db.transaction(function (tx) {
    tx.executeSql('DELETE FROM LOGS WHERE id=?', [id]);
});

更新记录

更新记录的格式如下:

db.transaction(function (tx) {
    tx.executeSql('UPDATE LOGS SET log="www.w3cschool.cc" WHERE id=2');
});

你也可以使用动态值来更新记录:

db.transaction(function (tx) {
    tx.executeSql('UPDATE LOGS SET log="www.w3cschool.cc" WHERE id=?', [id]);
});

完整实例

以下是一个完整的示例,展示了如何创建数据库、插入数据、删除记录、更新记录并读取数据:

var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);
var msg;

db.transaction(function (tx) {
    tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "菜鸟教程")');
    tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "www.runoob.com")');
    msg = '
<p>数据表已创建,且插入了两条数据。</p>';
    document.querySelector('#status').innerHTML = msg;
});

db.transaction(function (tx) {
    tx.executeSql('DELETE FROM LOGS WHERE id=1');
    msg = '
<p>删除 id 为 1 的记录。</p>';
    document.querySelector('#status').innerHTML = msg;
});

db.transaction(function (tx) {
    tx.executeSql('UPDATE LOGS SET log="www.w3cschool.cc" WHERE id=2');
    msg = '
<p>更新 id 为 2 的记录。</p>';
    document.querySelector('#status').innerHTML = msg;
});

db.transaction(function (tx) {
    tx.executeSql('SELECT * FROM LOGS', [], function (tx, results) {
        var len = results.rows.length;
        var msg = "
<p>查询记录条数: " + len + "</p>";
        document.querySelector('#status').innerHTML += msg;
        for (var i = 0; i < len; i++) {
            msg = "
<p><b>" + results.rows.item(i).log + "</b></p>";
            document.querySelector('#status').innerHTML += msg;
        }
    }, null);
});

IndexedDB:现代客户端存储解决方案

IndexedDB 是一种基于浏览器的 NoSQL 数据库,用于在客户端持久化存储大量结构化数据。与 Web SQL 不同,IndexedDB 是异步的,不会阻塞主线程,适合离线应用程序、缓存等场景。

IndexedDB 特性

  • 键值对存储:数据以键值对的形式存储在对象存储(object store)中。
  • 事务支持:所有数据操作必须在事务内完成,以确保数据一致性和完整性。
  • 异步 API:所有操作都是异步的,不会阻塞 UI 线程,使用事件回调或 Promises 来处理结果。
  • 版本控制:数据库使用版本号来管理数据库的架构(如创建或修改对象存储)。
  • 索引:支持对数据的字段建立索引,以加快查询速度。
  • 离线支持:数据可以持久化存储并在断网情况下继续访问,非常适合构建离线 Web 应用。

IndexedDB 方法

  1. indexedDB.open:用于打开现有数据库或创建新数据库。

  2. db.createObjectStore:在 onupgradeneeded 事件中创建对象存储(类似表)。

  3. objectStore.add:在事务中向对象存储中添加数据。

  4. objectStore.get:根据键值从对象存储中获取数据。

  5. objectStore.put:更新现有记录,若记录不存在则插入。

  6. objectStore.delete:根据键值删除记录。

  7. db.transaction:创建事务,指定对象存储名称和事务模式(readonly 或 readwrite)。

  8. objectStore.createIndex:为对象存储中的字段创建索引,以便更快的查询。

IndexedDB 应用实例

以下是一个完整的 IndexedDB 实例,用于创建数据库、插入数据、查询数据并更新数据:

// 打开或创建数据库
var request = indexedDB.open('myDatabase', 1);

// 如果数据库版本变化或首次创建时触发
request.onupgradeneeded = function (event) {
    var db = event.target.result;
    // 创建对象存储(表),设置主键为 'id'
    var objectStore = db.createObjectStore('customers', { keyPath: 'id' });
    // 为 'name' 字段创建索引
    objectStore.createIndex('name', 'name', { unique: false });
};

// 打开数据库成功
request.onsuccess = function (event) {
    var db = event.target.result;

    // 插入数据
    var transaction = db.transaction(['customers'], 'readwrite');
    var objectStore = transaction.objectStore('customers');

    objectStore.add({ id: 1, name: 'John Doe', email: 'john@example.com' });
    objectStore.add({ id: 2, name: 'Jane Doe', email: 'jane@example.com' });

    transaction.oncomplete = function () {
        console.log('Transaction completed: data added.');
    };

    transaction.onerror = function (event) {
        console.error('Transaction failed:', event);
    };

    // 查询数据
    var queryTransaction = db.transaction(['customers'], 'readonly');
    var queryObjectStore = queryTransaction.objectStore('customers');

    var request = queryObjectStore.get(1);
    request.onsuccess = function (event) {
        console.log('Customer:', event.target.result);
    };

    // 更新数据
    var updateTransaction = db.transaction(['customers'], 'readwrite');
    var updateObjectStore = updateTransaction.objectStore('customers');

    var request = updateObjectStore.put({ id: 1, name: 'John Updated', email: 'john@example.com' });
    request.onsuccess = function () {
        console.log('Customer updated successfully.');
    };
};

总结

虽然 Web SQL 仍然在某些老旧浏览器中可用,但鉴于其未来不确定性和不再有广泛支持,建议开发者转向使用 IndexedDB。IndexedDB 提供了更强大的功能和更好的性能,适用于现代 Web 应用的客户端存储需求。希望本文能帮助你更好地理解和使用这两种客户端存储技术。