欢迎到专业群( uni-app 官方技术交流群 1 ) 咨询,群中有相关专业的管理员和群友。
这个问题在 uni-app 开发中非常经典,本质上是 热更新(HBuilderX 基座调试时的热重载)导致数据库连接句柄失效,但应用没有重新打开数据库导致的。
根据知识库中的官方回复和社区经验,解决方案如下:
核心原因
在 iOS 或部分 Android 环境下,HBuilderX 触发代码热更新时,底层的原生引擎会重启或重置部分状态,之前通过 plus.sqlite.openDatabase 打开的数据库连接会被关闭或变为只读状态。此时如果代码逻辑中判断“数据库已打开”就直接执行写入操作,就会报 readonly database 错误。
解决方案:在操作前重新打开数据库
最稳妥的做法是,在每次执行增删改查之前,不要依赖之前打开的连接状态。你应该在操作前先调用 plus.sqlite.isOpenDatabase 判断,如果已打开则先关闭再重新打开,或者封装一个“获取可用数据库连接”的方法。
方案一:简单粗暴的重启连接(推荐用于调试阶段)
在 App.vue 的 onLaunch 或页面初始化时,不再直接打开数据库,而是封装一个 getDB 函数:
// 数据库操作工具 js
const dbName = 'myAppDB';
const dbPath = '_doc/myAppDB.db';
function openDB() {
return new Promise((resolve, reject) => {
// 1. 先尝试关闭可能残留的只读连接
plus.sqlite.closeDatabase({
name: dbName,
success: () => {
console.log('旧连接已关闭,准备重新打开');
realOpen(resolve, reject);
},
fail: () => {
// 关闭失败通常意味着本来就没打开,直接尝试打开即可
realOpen(resolve, reject);
}
});
});
}
function realOpen(resolve, reject) {
plus.sqlite.openDatabase({
name: dbName,
path: dbPath,
success: (e) => {
console.log('数据库重新打开成功');
resolve(e);
},
fail: (e) => {
console.error('数据库打开失败', e);
reject(e);
}
});
}
// 在需要操作数据库的地方调用
async function insertData() {
await openDB(); // 确保每次操作前都是全新的连接
// 执行 insert 或 update...
}
本助手使用国产模型,生成代码可能不准确。专业的代码生成需要全球顶尖的AI Coding模型。推荐使用uni-agent
方案二:iOS 设备在热重启前主动关闭(针对线上 wgt 热更新)
如果你指的是 wgt 包的线上热更新(调用 plus.runtime.install 后 plus.runtime.restart() 重启应用),在 iOS 上重启后也容易出现只读问题。根据知识库中的社区反馈,可以在调用 restart() 之前,主动关闭数据库:
plus.runtime.install(downloadResult.tempFilePath, {
force: false
}, function() {
// 安装成功,准备重启
try {
plus.sqlite.closeDatabase({ name: 'myAppDB' });
} catch (e) {
console.log('关闭数据库忽略报错');
}
plus.runtime.restart();
});
本助手使用国产模型,生成代码可能不准确。专业的代码生成需要全球顶尖的AI Coding模型。推荐使用uni-agent
重启后,应用重新走 onLaunch 流程,正常打开数据库即可。
特别注意
- 鸿蒙平台 (HarmonyOS):根据知识库记录,鸿蒙平台目前对
plus.sqlite 和热更新(wgt)的支持尚不完善,有开发者反馈 plus.runtime.install 执行后重启未生效或第二次更新报错。如果是鸿蒙平台遇到此问题,暂时没有完美的官方修复方案,建议关注官方后续更新或尝试整包更新。
- 不要使用
isOpenDatabase 作为免开库的依据:很多开发者喜欢先判断 isOpenDatabase,如果为 true 就不重新打开。但在热更新场景下,这个连接虽然显示“打开”,实际上已经是只读状态了,必须关闭重开。
如果上述方案仍然无法解决,可以参考社区一个临时处理方案:在 iOS 设备 restart 之前务必关闭数据库,让重启流程自然触发重新打开。更多讨论见 ask 社区相关帖子。
1 个回复
Ask小助手 - Ask社区AI助手
这个问题在 uni-app 开发中非常经典,本质上是 热更新(HBuilderX 基座调试时的热重载)导致数据库连接句柄失效,但应用没有重新打开数据库导致的。
根据知识库中的官方回复和社区经验,解决方案如下:
核心原因
在 iOS 或部分 Android 环境下,HBuilderX 触发代码热更新时,底层的原生引擎会重启或重置部分状态,之前通过
plus.sqlite.openDatabase打开的数据库连接会被关闭或变为只读状态。此时如果代码逻辑中判断“数据库已打开”就直接执行写入操作,就会报readonly database错误。解决方案:在操作前重新打开数据库
最稳妥的做法是,在每次执行增删改查之前,不要依赖之前打开的连接状态。你应该在操作前先调用
plus.sqlite.isOpenDatabase判断,如果已打开则先关闭再重新打开,或者封装一个“获取可用数据库连接”的方法。方案一:简单粗暴的重启连接(推荐用于调试阶段)
在
App.vue的onLaunch或页面初始化时,不再直接打开数据库,而是封装一个getDB函数:方案二:iOS 设备在热重启前主动关闭(针对线上 wgt 热更新)
如果你指的是 wgt 包的线上热更新(调用
plus.runtime.install后plus.runtime.restart()重启应用),在 iOS 上重启后也容易出现只读问题。根据知识库中的社区反馈,可以在调用restart()之前,主动关闭数据库:重启后,应用重新走
onLaunch流程,正常打开数据库即可。特别注意
plus.sqlite和热更新(wgt)的支持尚不完善,有开发者反馈plus.runtime.install执行后重启未生效或第二次更新报错。如果是鸿蒙平台遇到此问题,暂时没有完美的官方修复方案,建议关注官方后续更新或尝试整包更新。isOpenDatabase作为免开库的依据:很多开发者喜欢先判断isOpenDatabase,如果为true就不重新打开。但在热更新场景下,这个连接虽然显示“打开”,实际上已经是只读状态了,必须关闭重开。如果上述方案仍然无法解决,可以参考社区一个临时处理方案:在 iOS 设备
restart之前务必关闭数据库,让重启流程自然触发重新打开。更多讨论见 ask 社区相关帖子。要回复问题请先登录或注册
公告
更多>相关问题