经常被问"该用哪个",我的答案一直很朴素:看有没有并发写入。

#判断清单

  • 单机、单用户、数据量几十万行以内 → 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 以内比较稳妥。