You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React Native中SQLite插入数据提示数据库已打开及保存异常解决

解决React Native SQLite插入无反应及"database already open"错误问题

我仔细看了你的代码和问题描述,核心问题出在数据库连接管理混乱API参数使用错误上,这也是导致部分设备正常、部分设备失败的原因。下面一步步拆解问题并给出修复方案:

问题分析

  1. openDatabase参数顺序完全错误
    react-native-sqlite-storage的openDatabase正确参数顺序是:(name, version, displayName, size, callback),但你在initDB里把database_sizedatabase_version的位置搞反了,这会导致部分设备无法正确初始化数据库,直接静默失败。

  2. 重复创建数据库连接
    每次调用createUserusers方法时,都会调用initDB新建一个数据库连接,而不是复用已有的连接。这会导致多个连接同时存在,触发"database already open"错误,同时多连接冲突会让插入操作无法正常执行。

  3. Promise错误处理缺失
    很多catch块是空的或者没有正确输出错误信息,导致部分设备的失败原因无法被捕获,看起来像是"无报错日志"。

  4. 不合理的数据库关闭时机
    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让代码更易读。

使用提示

  1. 创建Database实例时,只需要创建一次(比如在App.js里初始化,全局使用),不要每次操作都新建实例。
  2. 如果需要确保数据库初始化完成后再进行操作,可以在组件里等待initDB完成:
const db = new Database();
// 等待初始化完成(更优雅的方式可以给initDB添加状态监听)
await new Promise(resolve => setTimeout(resolve, 1000));

这样修改后,就能解决"database already open"错误,同时保证所有设备都能正常执行插入和查询操作。

内容的提问来源于stack exchange,提问作者dody.ac

火山引擎 最新活动