React Native中SQLite插入数据提示数据库已打开及保存异常解决
解决React Native SQLite插入无反应及"database already open"错误问题
我仔细看了你的代码和问题描述,核心问题出在数据库连接管理混乱和API参数使用错误上,这也是导致部分设备正常、部分设备失败的原因。下面一步步拆解问题并给出修复方案:
问题分析
openDatabase参数顺序完全错误
react-native-sqlite-storage的openDatabase正确参数顺序是:(name, version, displayName, size, callback),但你在initDB里把database_size和database_version的位置搞反了,这会导致部分设备无法正确初始化数据库,直接静默失败。重复创建数据库连接
每次调用createUser或users方法时,都会调用initDB新建一个数据库连接,而不是复用已有的连接。这会导致多个连接同时存在,触发"database already open"错误,同时多连接冲突会让插入操作无法正常执行。Promise错误处理缺失
很多catch块是空的或者没有正确输出错误信息,导致部分设备的失败原因无法被捕获,看起来像是"无报错日志"。不合理的数据库关闭时机
在createUser里,事务刚完成就立即关闭数据库,但实际上数据库连接应该复用,而不是每次操作后都关闭——频繁打开关闭连接不仅效率低,还可能导致操作未完成就被中断。
修复后的完整代码
import SQLite from "react-native-sqlite-storage"; SQLite.DEBUG(true); SQLite.enablePromise(true); const database_name = "mst_person.db"; const database_version = "1.0"; const database_displayname = "SQLite React Offline Database"; const database_size = 200000; export default class Database { constructor() { this.db = null; // 用实例变量保存数据库连接,实现复用 this.initDB(); // 初始化时只打开一次连接 } async initDB() { try { console.log('Plugin integrity Check...'); await SQLite.echoTest(); console.log('Integrity Check Passed'); console.log('Open Database...'); // 修复参数顺序:name, version, displayName, size this.db = await SQLite.openDatabase( database_name, database_version, database_displayname, database_size ); console.log('Database open'); // 检查表是否存在,不存在则创建 try { await this.db.executeSql('SELECT * FROM users'); console.log('Database Ready'); } catch (error) { console.log('Database not yet Ready, creating table...'); await this.db.transaction((trx) => { trx.executeSql('CREATE TABLE IF NOT EXISTS users (userId TEXT PRIMARY KEY, userName TEXT)'); }); console.log('Table Create Success'); } } catch (error) { console.error('Database initialization failed:', error); } } closeDatabase() { if (this.db) { console.log('Closing database'); this.db.close() .then(() => { console.log('DB Closed'); this.db = null; }) .catch((error) => { console.error('Close Database failed:', error); }); } else { console.log('Database Was Not Opened'); } } async users() { const users = []; try { if (!this.db) await this.initDB(); // 确保连接存在 const [tx, results] = await this.db.executeSql('SELECT * FROM users', []); console.log("Query completed"); const len = results.rows.length; for (let i = 0; i < len; i++) { const row = results.rows.item(i); console.log(`User ID: ${row.userId}, User Name: ${row.userName}`); users.push({ userId: row.userId, userName: row.userName }); } console.log(users); return users; } catch (err) { console.error('Fetch users failed:', err); return []; } } async createUser(user) { try { if (!this.db) await this.initDB(); // 确保连接存在 const [tx, results] = await this.db.executeSql( 'INSERT INTO users VALUES (?, ?)', [user.userId, user.userName] ); console.log('User created successfully:', results); return results; } catch (err) { console.error('Create user failed:', err); throw err; // 抛出错误让调用者处理 } } }
关键修改点说明
- 连接复用:在类的constructor里初始化数据库连接,用
this.db保存,后续所有操作都复用这个连接,避免重复打开导致的错误。 - 修复参数顺序:调整
openDatabase的参数顺序为正确的name, version, displayName, size。 - 完善错误处理:所有异步操作都添加
try/catch并输出详细错误信息,方便排查问题。 - 移除不必要的事务关闭:不再每次操作后关闭数据库,而是在应用退出时调用
closeDatabase即可。 - 简化逻辑:移除无用的
initDb方法,合并初始化逻辑到initDB,并使用async/await让代码更易读。
使用提示
- 创建Database实例时,只需要创建一次(比如在App.js里初始化,全局使用),不要每次操作都新建实例。
- 如果需要确保数据库初始化完成后再进行操作,可以在组件里等待
initDB完成:
const db = new Database(); // 等待初始化完成(更优雅的方式可以给initDB添加状态监听) await new Promise(resolve => setTimeout(resolve, 1000));
这样修改后,就能解决"database already open"错误,同时保证所有设备都能正常执行插入和查询操作。
内容的提问来源于stack exchange,提问作者dody.ac




