大家好!今天我要和大家分享一个前端开发者也能轻松掌握的数据库神器------SQLite3。作为一名经常在掘金分享技术心得的创作者,我发现很多前端同学对数据库总有些"敬而远之",觉得那是后端的专属领域。但其实,SQLite3这个轻量级数据库完全可以成为我们前端开发者的好朋友!
为什么选择SQLite3?
在我们开始编码之前,先聊聊为什么我要推荐SQLite3。
MySQL确实强大,但就像开一辆重型卡车去买菜------功能过剩了!它需要独立的服务器进程,配置复杂,对于小型项目来说太重了。
MongoDB这类NoSQL数据库灵活是灵活,但就像把乐高积木全倒在地上------有时候我们真的需要一些结构化的约束啊!
这时候,SQLite3就像一辆灵巧的自行车:轻便(整个数据库就是一个文件)、无需配置(不需要单独的服务)、使用标准的SQL语法(学习成本低),而且它已经被内置在无数应用中(包括你的手机里可能就有几十个应用在使用它)。
SQLite3的三大优势
- 零配置:不用安装服务器,不用设置用户权限
- 无服务器:直接操作磁盘文件
- 全功能:支持大多数标准SQL92特性
初识SQLite3
让我们从一个实际的例子开始。假设我们要管理一个公司员工信息系统,需要记录:
- 姓名
- 工资
- 部门
初始化数据库
首先,我们需要创建一个数据库文件并建立连接:
javascript
const sqlite3 = require('sqlite3').verbose();
// 注意:实际开发中请使用异步版本或Promise封装
const db = new sqlite3.Database('./company.db',
async (err) => {
if (err) {
console.error('数据库打开失败', err);
return;
}
console.log('数据库打开成功');
// 数据库操作句柄
await db.run(`
CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department TEXT NOT NULL,
salary INTEGER NOT NULL
)
`);
}
);
这段代码做了什么呢?它尝试连接(或创建)一个名为company.db
的数据库文件。如果文件不存在,SQLite会自动创建它;如果存在,就直接打开。
创建我们的第一张表
根据数据库设计三大范式(是的,即使是轻量级SQLite我们也应该遵循良好实践),我们来创建员工表:
javascript
db.run(`CREATE TABLE IF NOT EXISTS employees (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
department TEXT NOT NULL,
salary INTEGER NOT NULL
)`, (err) => {
if (err) {
console.error('创建表时出错:', err.message);
return;
}
console.log('员工表已创建或已存在');
});
这里有几个关键点:
IF NOT EXISTS
:避免重复创建报错PRIMARY KEY AUTOINCREMENT
:自动增长的ID主键- 指定了字段类型(TEXT, INTEGER)和约束(NOT NULL)
CRUD操作实战
1. 创建(Create) - 添加新员工
javascript
const addEmployee = (name, department, salary) => {
db.run(`INSERT INTO employees (name, department, salary) VALUES (?, ?, ?)`,
[name, department, salary],
function(err) {
if (err) {
return console.error('添加员工失败:', err.message);
}
console.log(`成功添加员工 ${name},ID为 ${this.lastID}`);
});
};
// 使用示例
addEmployee('张三', '技术部', 15000);
addEmployee('李四', '市场部', 12000);
注意这里使用了参数化查询(?
占位符),这是防止SQL注入的重要实践!
2. 读取(Read) - 查询员工信息
javascript
const getEmployees = (callback) => {
db.all('SELECT * FROM employees', [], (err, rows) => {
if (err) {
console.error('查询员工失败:', err.message);
return callback(err);
}
callback(null, rows);
});
};
// 使用示例
getEmployees((err, employees) => {
if (err) return;
console.log('所有员工:', employees);
});
db.all()
获取所有结果,对于大数据集要小心使用。如果只需要一行,可以用db.get()
。
3. 更新(Update) - 给员工加薪
javascript
const giveRaise = (id, amount) => {
db.run(`UPDATE employees SET salary = salary + ? WHERE id = ?`,
[amount, id],
function(err) {
if (err) {
return console.error('加薪失败:', err.message);
}
console.log(`成功为ID ${id}的员工加薪,影响了 ${this.changes} 条记录`);
});
};
// 使用示例
giveRaise(1, 3000); // 给ID为1的员工加薪3000
4. 删除(Delete) - 解雇员工
javascript
const fireEmployee = (id) => {
db.run(`DELETE FROM employees WHERE id = ?`,
[id],
function(err) {
if (err) {
return console.error('解雇失败:', err.message);
}
console.log(`成功解雇ID ${id}的员工,影响了 ${this.changes} 条记录`);
});
};
// 使用示例
fireEmployee(2); // 解雇ID为2的员工
高级技巧
事务处理
当需要执行多个相关操作时,事务可以保证原子性:
javascript
const transferDepartment = (employeeId, newDept) => {
db.serialize(() => {
db.run('BEGIN TRANSACTION');
db.run('UPDATE employees SET department = ? WHERE id = ?',
[newDept, employeeId],
function(err) {
if (err) {
return db.run('ROLLBACK');
}
console.log(`部门调动成功`);
});
db.run('COMMIT');
});
};
使用Promise封装
回调地狱?不存在的!我们可以用Promise封装:
javascript
const dbPromise = {
run: (sql, params) => new Promise((resolve, reject) => {
db.run(sql, params, function(err) {
if (err) reject(err);
else resolve(this);
});
}),
get: (sql, params) => new Promise((resolve, reject) => {
db.get(sql, params, (err, row) => {
if (err) reject(err);
else resolve(row);
});
}),
all: (sql, params) => new Promise((resolve, reject) => {
db.all(sql, params, (err, rows) => {
if (err) reject(err);
else resolve(rows);
});
})
};
// 使用示例
async function getHighPaidEmployees() {
try {
const employees = await dbPromise.all(
'SELECT * FROM employees WHERE salary > ?',
[10000]
);
console.log('高薪员工:', employees);
} catch (err) {
console.error('查询失败:', err);
}
}
实际应用场景
SQLite在前端/客户端开发中大有可为:
- Electron应用:本地数据存储
- Node.js小型服务:快速原型开发
- 工具脚本:数据处理和分析
- 浏览器扩展:存储用户配置和数据
性能优化小贴士
- 批量操作:使用事务批量插入数据,速度可以提升数百倍
- 合理使用索引:对经常查询的字段创建索引
- 控制返回数据量 :避免不必要的
SELECT *
- 适时关闭连接:长时间不用的连接应该关闭
常见陷阱与解决方案
问题1 :并发写入冲突
解决 :SQLite默认一次只允许一个写操作,可以使用busy_timeout
设置或实现重试逻辑
问题2 :数据类型灵活导致的问题
解决:SQLite使用动态类型,建议在应用层加强类型检查
问题3 :数据库文件被锁定
解决:确保每次操作后都正确关闭连接,避免多个进程同时写入
总结
SQLite3就像数据库世界里的瑞士军刀------小巧但功能强大。通过本文的学习,你应该已经掌握了:
- 如何创建和连接SQLite数据库
- 基本的CRUD操作
- 事务处理和Promise封装
- 实际应用场景和优化技巧
记住,技术选型没有银弹。对于需要简单、嵌入式、零配置数据库的场景,SQLite3绝对是你的不二之选。而对于复杂的、高并发的企业级应用,你可能还是需要考虑MySQL。
希望这篇指南能帮你打开SQLite3的大门!如果你有任何问题或想分享你的SQLite使用经验,欢迎在评论区留言讨论。下次见!