runInTransaction<T> method

Future<T> runInTransaction<T>(
  1. Future<T> action()
)

Run action inside a database transaction on a single pinned connection.

The default implementation issues raw BEGIN / COMMIT / ROLLBACK via rawQuery. This is correct for single-connection clients such as SQLite, but unreliable on connection-pooled drivers (Postgres, MySQL) where each rawQuery call may land on a different physical connection — making the transaction a silent no-op.

Pooled drivers should override this method to acquire one connection, keep it pinned for the duration of action, then release it:

@override
Future<T> runInTransaction<T>(Future<T> Function() action) =>
    _pool.withConnection((conn) => conn.runTx((_) => action()));

The Migrator calls this when MigrationConfig.disableTransactions is false. It defaults to true precisely because pooled drivers have not yet overridden this method.

Implementation

Future<T> runInTransaction<T>(Future<T> Function() action) async {
  await rawQuery('BEGIN', const []);
  try {
    final result = await action();
    await rawQuery('COMMIT', const []);
    return result;
  } catch (e) {
    try {
      await rawQuery('ROLLBACK', const []);
    } catch (_) {}
    rethrow;
  }
}