什么是 HTML5 Web SQL 数据库?
在移动互联网时代,前端开发不再只是“展示页面”那么简单。越来越多的 Web 应用需要在用户本地存储数据,比如离线笔记、待办事项列表、购物车信息等。传统的 Cookie 和 LocalStorage 虽然简单,但它们的容量有限,且不适合存储结构化数据。
这时,HTML5 Web SQL 数据库就登场了。它是一种基于 SQLite 的客户端数据库解决方案,允许我们在浏览器中创建、读取、更新和删除结构化数据。虽然它已被 W3C 标准弃用(取而代之的是 IndexedDB),但在一些老项目或特定场景中依然具有实用价值。
你可以把 HTML5 Web SQL 数据库想象成一个“微型的本地数据库”,就像你手机里安装的某个 App 所使用的数据存储系统。它不依赖网络,数据存在用户的设备上,速度也比远程数据库快得多。
注意:尽管 Web SQL 已被标记为“废弃”,但目前主流浏览器(如 Chrome、Safari)仍支持。如果你在维护旧项目或开发离线优先的 Web 应用,它依然是一个可选项。
如何打开并操作 HTML5 Web SQL 数据库?
要使用 HTML5 Web SQL 数据库,首先需要通过 JavaScript 的 window.openDatabase 方法打开一个数据库实例。这个方法的语法如下:
const db = window.openDatabase(name, version, description, size);
name:数据库名称,字符串类型,比如'myAppDB'version:数据库版本号,比如'1.0',用于版本管理description:数据库描述,可选,用于说明用途size:数据库大小,单位为字节,比如1024 * 1024表示 1MB
下面是一个完整的打开数据库示例:
// 打开或创建一个名为 'todoDB' 的数据库
const db = window.openDatabase('todoDB', '1.0', '我的待办事项数据库', 1024 * 1024);
// 如果数据库打开成功,会在控制台输出提示
db.transaction(function(tx) {
console.log('数据库已成功打开');
});
⚠️ 重要提示:
openDatabase是异步操作,但其返回的db对象可以立即用于后续操作。所有数据库操作都必须通过transaction()方法进行,这是保证数据一致性的关键。
创建表与插入数据
数据库打开后,下一步就是创建表。就像你在 Excel 中创建一个表格一样,你需要定义列名和数据类型。
在 HTML5 Web SQL 数据库中,支持的数据类型包括:TEXT、INTEGER、REAL(浮点数)、BLOB(二进制数据)。注意:它不支持 DATE 类型,但你可以用 TEXT 存储日期字符串。
我们来创建一个“待办事项”表:
// 使用事务创建表
db.transaction(function(tx) {
// 执行 SQL 语句创建表
tx.executeSql(
'CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, completed BOOLEAN DEFAULT 0, created_at TEXT)',
[], // 参数数组,这里没有参数
function(tx, result) {
console.log('表创建成功');
},
function(tx, error) {
console.error('创建表失败:', error.message);
}
);
});
CREATE TABLE IF NOT EXISTS:如果表不存在才创建id INTEGER PRIMARY KEY AUTOINCREMENT:主键,自动递增title TEXT NOT NULL:任务标题,不能为空completed BOOLEAN DEFAULT 0:是否完成,0 表示未完成,1 表示完成created_at TEXT:创建时间,用字符串存储
创建完表后,我们来插入一条数据:
// 插入一条待办事项
db.transaction(function(tx) {
tx.executeSql(
'INSERT INTO todos (title, completed, created_at) VALUES (?, ?, ?)',
['学习 HTML5 Web SQL 数据库', false, new Date().toISOString()],
function(tx, result) {
console.log('数据插入成功,新记录 ID 为:', result.insertId);
},
function(tx, error) {
console.error('插入数据失败:', error.message);
}
);
});
?是占位符,防止 SQL 注入result.insertId返回新插入记录的主键 ID
查询与更新数据
插入数据后,我们当然需要查询它。使用 SELECT 语句可以获取数据,配合 executeSql 的回调函数处理结果。
// 查询所有待办事项
db.transaction(function(tx) {
tx.executeSql(
'SELECT * FROM todos ORDER BY created_at DESC',
[],
function(tx, results) {
console.log('查询到 ' + results.rows.length + ' 条记录');
// 遍历查询结果
for (let i = 0; i < results.rows.length; i++) {
const row = results.rows.item(i);
console.log(
`ID: ${row.id}, 标题: ${row.title}, 完成: ${row.completed ? '是' : '否'}, 时间: ${row.created_at}`
);
}
},
function(tx, error) {
console.error('查询失败:', error.message);
}
);
});
results.rows.length:返回结果的行数results.rows.item(i):获取第 i 行的数据对象ORDER BY created_at DESC:按创建时间倒序排列
更新数据也很简单。假设我们要把某条任务标记为“已完成”:
// 将 ID 为 1 的任务设为已完成
db.transaction(function(tx) {
tx.executeSql(
'UPDATE todos SET completed = 1 WHERE id = ?',
[1],
function(tx, result) {
if (result.rowsAffected > 0) {
console.log('更新成功,影响了 ' + result.rowsAffected + ' 行');
} else {
console.log('未找到 ID 为 1 的记录');
}
},
function(tx, error) {
console.error('更新失败:', error.message);
}
);
});
UPDATE语句用于修改现有数据WHERE id = ?精准定位要更新的记录result.rowsAffected返回受影响的行数
删除数据与清理数据库
当任务完成或数据过期时,我们需要删除记录。删除操作也通过 executeSql 实现:
// 删除 ID 为 1 的待办事项
db.transaction(function(tx) {
tx.executeSql(
'DELETE FROM todos WHERE id = ?',
[1],
function(tx, result) {
if (result.rowsAffected > 0) {
console.log('删除成功,共删除 ' + result.rowsAffected + ' 条记录');
} else {
console.log('未找到要删除的记录');
}
},
function(tx, error) {
console.error('删除失败:', error.message);
}
);
});
如果想彻底清空整个表,可以使用 DELETE FROM todos,但不会重置主键自增。
📌 小贴士:若要重置自增主键,可以使用
DELETE FROM todos; VACUUM;,但VACUUM不是所有浏览器都支持。
实际案例:简易待办事项应用
让我们整合前面的知识,做一个简单的待办事项应用。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>HTML5 Web SQL 数据库待办应用</title>
</head>
<body>
<h2>我的待办事项</h2>
<input type="text" id="taskInput" placeholder="输入任务内容" />
<button id="addBtn">添加任务</button>
<ul id="taskList"></ul>
<script>
// 打开数据库
const db = window.openDatabase('todoDB', '1.0', '待办事项数据库', 1024 * 1024);
// 创建表(首次运行时)
db.transaction(function(tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS todos (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, completed BOOLEAN DEFAULT 0, created_at TEXT)',
[],
function() {
console.log('表已创建或已存在');
},
function(err) {
console.error('创建表失败:', err.message);
}
);
});
// 添加任务
document.getElementById('addBtn').addEventListener('click', function() {
const input = document.getElementById('taskInput');
const title = input.value.trim();
if (!title) return;
db.transaction(function(tx) {
tx.executeSql(
'INSERT INTO todos (title, completed, created_at) VALUES (?, ?, ?)',
[title, false, new Date().toISOString()],
function(tx, result) {
alert('任务添加成功!');
input.value = '';
loadTasks(); // 重新加载任务列表
},
function(err) {
alert('添加失败:' + err.message);
}
);
});
});
// 加载任务列表
function loadTasks() {
const list = document.getElementById('taskList');
list.innerHTML = '';
db.transaction(function(tx) {
tx.executeSql(
'SELECT * FROM todos ORDER BY created_at DESC',
[],
function(tx, results) {
for (let i = 0; i < results.rows.length; i++) {
const row = results.rows.item(i);
const li = document.createElement('li');
li.innerHTML = `
<span style="margin-right: 10px;">${row.title}</span>
<input type="checkbox" ${row.completed ? 'checked' : ''} data-id="${row.id}" />
<button data-id="${row.id}" style="margin-left: 5px;">删除</button>
`;
list.appendChild(li);
}
},
function(err) {
console.error('加载失败:', err.message);
}
);
});
}
// 监听复选框和删除按钮
document.body.addEventListener('click', function(e) {
const id = e.target.getAttribute('data-id');
if (!id) return;
if (e.target.type === 'checkbox') {
db.transaction(function(tx) {
tx.executeSql(
'UPDATE todos SET completed = ? WHERE id = ?',
[e.target.checked ? 1 : 0, id],
function() {
console.log('状态已更新');
}
);
});
} else if (e.target.tagName === 'BUTTON') {
db.transaction(function(tx) {
tx.executeSql(
'DELETE FROM todos WHERE id = ?',
[id],
function() {
alert('任务已删除');
loadTasks();
}
);
});
}
});
// 页面加载时加载任务
window.onload = loadTasks;
</script>
</body>
</html>
这个应用具备以下功能:
- 添加新任务
- 显示所有任务
- 切换完成状态
- 删除任务
- 数据持久化(即使刷新页面也保留)
总结与建议
HTML5 Web SQL 数据库虽然已被弃用,但它在特定场景下依然有其价值。尤其对于需要离线运行、结构化数据存储、且对兼容性要求不高的项目,它是一个简单高效的解决方案。
它的核心优势在于:
- 使用标准 SQL 语法,学习成本低
- 支持事务,保证数据一致性
- 数据存储在本地,无需网络请求
- 适合中小规模结构化数据管理
但也要注意它的局限性:
- 不支持跨浏览器统一标准(IndexedDB 是未来方向)
- 数据量受限于浏览器存储配额
- 不支持复杂查询和索引优化
如果你正在开发一个新项目,建议优先考虑 IndexedDB 或 PouchDB 等现代方案。但如果在维护旧项目或需要快速实现本地数据存储,HTML5 Web SQL 数据库依然是一个值得了解的工具。
本文介绍了 HTML5 Web SQL 数据库的基本用法,包括打开数据库、创建表、增删改查操作,以及一个完整的待办事项应用实例。希望你能通过实践掌握这一技术,为你的 Web 应用增添本地数据处理能力。