uni-app中SQLite仅支持App端,需自定义基座+插件;H5/小程序需用uni.setStorage或sql.js;App端初始化须await db.init()并try/catch建表,exec不支持多语句,字段名大小写敏感,无自动事务回滚。

uni-app 里 SQLite 不是开箱即用的
uni-app 官方不内置 SQLite 支持,uni.getSQLiteSync 和 uni.openDatabase 这类 API 在 H5 和小程序平台根本不存在,只在 App(iOS/Android)端通过原生插件或自定义基座才可能启用。直接写代码调用会报 undefined is not a function 或 not supported 错误。
真正能用 SQLite 的唯一路径:打包为 App,并使用「自定义调试基座」+「SQLite 插件」。H5 和微信小程序里想“本地存结构化数据”,得换方案——比如 uni.setStorage + JSON 模拟,或引入 sql.js(纯 wasm 实现,但体积大、不支持文件持久化)。
- App 端必须勾选「使用自定义调试基座」,否则真机调试时插件不生效
- 插件需从 DCloud 插件市场安装,常见的是
uni-plugin-sqlite,不是 npm install 就能用的 - 插件初始化后返回的 db 对象,方法名和 Web SQL 不同,比如没有
transaction,只有exec和selectAll
如何在 App 中正确初始化并执行 SQL
初始化不是调 openDatabase 就完事。插件返回的 db 是异步创建的,且首次打开会触发建库逻辑,如果 SQL 语句里有语法错误(比如漏了分号、用了 SQLite 不支持的类型别名),exec 会静默失败或抛出模糊错误 sqlite error: near "xxx"。
推荐写法是显式 await 初始化,并用 try/catch 包裹建表语句:
const db = uni.requireNativePlugin('SQLite');
await db.init({ name: 'mydb.db' });
try {
await db.exec('CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT);');
} catch (e) {
console.error('建表失败:', e.message); // 注意 e.message 才是真实错误
}
-
exec只接受单条语句,不能一次传多个CREATE或INSERT,否则报错 - 参数绑定要用
?占位符,不要字符串拼接,避免注入和引号转义问题 - 插入后想拿自增 ID,得用
lastInsertRowId字段,不是返回结果里的insertId
查询结果字段名大小写敏感且带双引号
SQLite 插件返回的查询结果(如 selectAll)中,字段名默认是建表时 SQL 里写的原始大小写,并且会被自动加上双引号。如果你建表写的是 CREATE TABLE user (Name TEXT),那结果里就是 {"Name": "张三"},而不是小写的 name。很多开发者直接按 JS 常规驼峰习惯去取 row.name,结果是 undefined。
- 建表时统一用小写下划线(如
user_name)或全小写(如name),避免歧义 - 查询后用
Object.keys(row)[0]或打印JSON.stringify(row)确认实际字段名 - 不建议依赖字段顺序取值(如
row[0]),插件版本更新可能影响返回结构
事务没回滚、数据看似“丢失”的真实原因
插件不提供标准的 beginTransaction/commit 接口,所谓“事务”只能靠 exec 批量执行多条语句实现。但只要其中一条失败,前面成功的不会自动回滚——SQLite 插件默认每条 exec 都是独立事务。
例如你连续调两次 exec 插入,第二条失败,第一条的数据就留在库里了。这不是 bug,是设计如此。
- 需要原子性操作时,把所有 SQL 合成一条字符串,用分号隔开,再传给单次
exec - 批量插入建议用
INSERT INTO ... VALUES (...), (...), (...)语法,比循环调exec快 10 倍以上 - App 杀进程后数据不会丢,但调试时频繁重装 App 可能清空沙盒,导致数据库被重建
SQLite 在 uni-app App 里不是“换个 API 就能用”的功能,它卡在原生能力、插件生命周期、SQL 兼容性三层交界上。最常被忽略的其实是:每次改了建表语句,得手动删掉旧数据库文件再试,否则 CREATE TABLE IF NOT EXISTS 根本不生效。

















