如何正确处理expo-sqlite的transactionAsync函数中的错误?

问题描述 投票:0回答:1

我注意到有些错误没有被抛出。 特别是由 UNIQUE 约束和重复主键引起的错误。

export const insertMetricGroup = async (db: SQLite.SQLiteDatabase, name: string, description: string = '', grpOrder: number = 0) => {
    await db.transactionAsync(async (tx) => {
        const idFromIncrementTable = await getAndIncreaseIncrementAsync(tx, null, 'MetricGroupTable');
        console.log(idFromIncrementTable);
        // THIS EXECUTES CORRECTLY
        const res1 = await tx.executeSqlAsync(`INSERT INTO MetricGroupTable
        (id, name, description, grpOrder)
        VALUES (?, ?, ?, ?)`, [idFromIncrementTable, name, description, grpOrder]);
        console.log(res1);

        // THIS DOES NOT (which is fine, since PK already exists)
        // HOWEVER executeSqlAsync function in this case never returns anything (res2 is never printed).
        const res2 = await tx.executeSqlAsync(`INSERT INTO MetricGroupTable
        (id, name, description, grpOrder)
        VALUES (?, ?, ?, ?)`, [idFromIncrementTable, name, description, grpOrder]);
        console.log(res2);
        await metricGroupReorder(tx);
      });
  };

getAndIncreaseIncrementAsync 方法从单独的增量表中返回一个增量数字。

上面的示例将表现得像 res2 处于待处理状态,而不会抛出任何错误或返回结果。 同样,sqlite 数据库的行为就像事务正在运行(锁定数据库)并且没有回滚或提交

如果我重新加载应用程序(我正在使用 expo go 移动应用程序在 Android 上测试应用程序),任何插入任何表的尝试都会以类似的方式挂起(即使是应该正常插入的查询,因为没有违反约束)进一步增加了先前交易无限期挂起的可能性。此问题将持续存在,直到数据库被删除:

const db: SQLite.SQLiteDatabase = await SQLite.openDatabase('HabitsDb.db');
await db.closeAsync();
await db.deleteAsync();

据我所知,transactionAsync 用于返回 resulterror 或结果集,但是由于此问题,大约一年前发生了更改: https://github.com/expo/expo/issues/23884

由于 javascript 的执行在错误点完全停止(这类似于我在其他项目中线程等待数据库上释放某些锁时所经历的情况) 软件包依赖性:

"dependencies": {
"@react-navigation/bottom-tabs": "^6.5.20",
"@react-navigation/native": "^6.1.17",
"@react-navigation/native-stack": "^6.9.26",
"expo": "~50.0.17",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-native": "0.73.6",
"react-native-popup-menu": "^0.16.1",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
"expo-sqlite": "~13.4.0"},

以下内容失败,结果相同,因此在 expo-sqlite lib 中更改返回类型的 git commit 可能不会导致错误:

export const insertMetricGroupLowLevel = async(db: SQLite.SQLiteDatabase, name: string, description: string = '', grpOrder: number = 0) => {
// validate data
if (name.length < 1)
{
    throw('NAME TO SHORT');
}
await db.execAsync([{ sql: 'BEGIN;', args: [] }], false);
try
{
  const res1: any = await getAndIncreaseIncrementAsyncLowLevel(db, 'MetricGroupTable');
  await db.execAsync([{ sql: `INSERT INTO MetricGroupTable
  (id, name, description, grpOrder)
  VALUES (?, ?, ?, ?);`, args: [res1, name, description, grpOrder] }], false);
  await db.execAsync([{ sql: `INSERT INTO MetricGroupTable
  (id, name, description, grpOrder)
  VALUES (?, ?, ?, ?);`, args: [res1, name, description, grpOrder] }], false);
  await metricGroupReorderLowLevel(db);
  await db.execAsync([{ sql: 'END;', args: [] }], false);
  console.log('INSERTED METRIC GROUP')
}
catch(error)
{
  await db.execAsync([{ sql: 'ROLLBACK;', args: [] }], false);
  console.log('FAILED INSERT OF METRIC GROUP', error);
}

}

表格:

CREATE TABLE IF NOT EXISTS MetricGroupTable (
      id INTEGER PRIMARY KEY,
      name TEXT NOT NULL,
      description TEXT NOT NULL,
      grpOrder INTEGER NOT NULL
    );

CREATE TABLE IF NOT EXISTS IncrementsTable (
      id INTEGER PRIMARY KEY,
      name TEXT NOT NULL,
      value INTEGER NOT NULL
    );
react-native expo expo-sqlite
1个回答
0
投票

expo-sqlite 收到新的重大更新(SDK 51 和版本 14.0.3)

虽然接口、方法和函数调用发生了很大的变化,但我可以确认现在唯一的约束违规会抛出错误,而不是让事务挂起

await db.withExclusiveTransactionAsync(async (tx) => {
    const idFromIncrementTable = await getAndIncreaseIncrementAsync(tx, null, 'MetricGroupTable');
    console.log(idFromIncrementTable);
    const statement = await tx.prepareAsync(`INSERT INTO MetricGroupTable
    (id, name, description, grpOrder)
    VALUES (?, ?, ?, ?);`);
    await statement.executeAsync(idFromIncrementTable, name, description, grpOrder);
    console.log('FIRST');
    await statement.executeAsync(idFromIncrementTable, name, description, grpOrder);
    console.log('SECOND'); // this does not print, but transaction throws an error as it should
    await metricGroupReorder(tx);
    });

数据库上没有挂锁或任何东西

© www.soinside.com 2019 - 2024. All rights reserved.