Как правильно обрабатывать ошибки в функции транзакцииAsync expo-sqlite?

Я заметил, что некоторые ошибки не выдаются. В частности, ошибки, вызванные ограничением 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.info(idFromIncrementTable);
        // THIS EXECUTES CORRECTLY
        const res1 = await tx.executeSqlAsync(`INSERT INTO MetricGroupTable
        (id, name, description, grpOrder)
        VALUES (?, ?, ?, ?)`, [idFromIncrementTable, name, description, grpOrder]);
        console.info(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.info(res2);
        await metricGroupReorder(tx);
      });
  };

Метод getAndIncreaseIncrementAsync возвращает число для приращения из отдельной таблицы приращений.

Приведенный выше пример будет вести себя так, как будто res2 находится в ожидании, без каких-либо ошибок или возврата результата. Аналогично база данных sqlite ведет себя так, как будто транзакция выполняется (заблокированная база данных), а не откатывается или фиксируется.

Если я перезагружаю приложение (я тестирую приложение на Android с помощью мобильного приложения expo go), любая попытка вставки в любую таблицу будет зависать аналогичным образом (даже запросы, которые должны быть вставлены обычным образом, поскольку нет нарушения ограничений). увеличивая вероятность того, что предыдущая транзакция останется зависшей на неопределенный срок. Эта проблема будет сохраняться до тех пор, пока база данных не будет удалена:

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

Насколько я могу судить, транзакцияAsync раньше возвращала либо ошибку результата, либо набор результатов, однако это было изменено около года назад из-за этой проблемы: 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"},

Следующее не работает с тем же результатом, поэтому git commit в библиотеке expo-sqlite, которая изменила тип возвращаемого значения, вероятно, не вызвала ошибку:

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.info('INSERTED METRIC GROUP')
}
catch(error)
{
  await db.execAsync([{ sql: 'ROLLBACK;', args: [] }], false);
  console.info('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
    );
Умерло ли Create-React-App?
Умерло ли Create-React-App?
В этом документальном фильме React.dev мы исследуем, мертв ли Create React App (CRA) и какое будущее ждет этот популярный фреймворк React.
Освоение React Native: Пошаговое руководство для начинающих
Освоение React Native: Пошаговое руководство для начинающих
React Native - это популярный фреймворк с открытым исходным кодом, используемый для разработки мобильных приложений. Он был разработан компанией...
В чем разница между react native и react ?
В чем разница между react native и react ?
React и React Native - два популярных фреймворка для создания пользовательских интерфейсов, но они предназначены для разных платформ. React - это...
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
От React к React Native: Руководство для начинающих по разработке мобильных приложений с использованием React
Если вы уже умеете работать с React, создание мобильных приложений для iOS и Android - это новое приключение, в котором вы сможете применить свои...
Хуки React: что это такое и как их использовать
Хуки React: что это такое и как их использовать
Хуки React - это мощная функция библиотеки React, которая позволяет разработчикам использовать состояние и другие возможности React без написания...
0
0
246
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

expo-sqlite получил новое крупное обновление (SDK 51 и версия 14.0.3)

Хотя интерфейсы, методы и вызовы функций были сильно изменены, я могу подтвердить, что теперь нарушение уникального ограничения вызывает ошибки, как и должно быть, а не приводит к зависанию транзакции.

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

в базе данных нет висячих блокировок или чего-то еще

Другие вопросы по теме

`tsc` продолжает отслеживать `node_modules`. Может ли кто-нибудь помочь мне решить эту проблему?
Ошибка в моем собственном коде реагирования с использованием обработчика жестов
Собственные данные React expo sqlite/next не отображаются в файле БД, пока файл открыт в браузере БД
Сбой приложения Expo при открытии с исключением в HostObject::get для реквизита «Качества»:
Отправка данных аудиозаписи в реальном времени через сокет
При открытии выставки на iOS происходит сбой с ошибкой: выход из xcrun с ненулевым кодом: 60 (домен = NSPOSIXErrorDomain, код = 60)
Обновить WebView до начального URL-адреса после переключения вкладок
Как перестать отображать новый файл в виде списка меню в маршрутизаторе Expo?
Ошибка: исключение в HostObject::get для prop > «NativeUnimoduleProxy» — происходит сбой виртуального устройства Android (AVD) при использовании Expo для тестирования приложения React Native
React Native Expo IOS - невозможно использовать собственные шрифты, никакое исправление от Google не помогло