Я заметил, что некоторые ошибки не выдаются. В частности, ошибки, вызванные ограничением 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
);
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);
});
в базе данных нет висячих блокировок или чего-то еще