经常被问"该用哪个",我的答案一直很朴素:看有没有并发写入。
#判断清单
- 单机、单用户、数据量几十万行以内 → SQLite
- 需要多用户同时写、需要远程访问、量级百万以上 → MySQL
- 需要外网部署但没有数据库运维能力 → 先 SQLite,留好升级口子
| 维度 | SQLite | MySQL |
|---|---|---|
| 部署 | 一个文件,零配置 | 需要服务与账号 |
| 并发写 | 库级锁 | 行级锁 |
| 网络访问 | 不支持 | 原生支持 |
| 备份 | 复制文件 | mysqldump |
| 运维成本 | 几乎为零 | 需要 |
#让代码同时支持两种
关键只有三点:占位符统一用 ?、时间统一存字符串、类型写法分开维护。
async function run(sql, params = []) {
if (driver === 'mysql') {
const [res] = await pool.query(sql, params);
return { insertId: res.insertId, affectedRows: res.affectedRows };
}
const info = sqlite.prepare(sql).run(params);
return { insertId: Number(info.lastInsertRowid), affectedRows: info.changes };
}建表语句按引擎生成:
const pk = driver === 'mysql'
? 'AUTO_INCREMENT PRIMARY KEY'
: 'PRIMARY KEY AUTOINCREMENT';这样业务代码完全不用关心底层,切换只改一行配置。
#一个真实教训
早期图省事把图片存在磁盘上,结果迁移服务器时路径全乱了。后来改成二进制直接存数据库:
CREATE TABLE assets (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
filename VARCHAR(255),
mime_type VARCHAR(128),
size INTEGER,
data LONGBLOB
);优点:备份只有一个库,不存在"库在、图没了"的情况。代价是库会变大,所以限制单文件 20MB 以内比较稳妥。