transaction<T> method
Executes action
in a transaction, which means that all its queries and
updates will be called atomically.
Returns the value of action
.
When action
throws an exception, the transaction will be reset and no
changes will be applied to the databases. The exception will be rethrown
by transaction.
The behavior of stream queries in transactions depends on where the stream was created:
- streams created outside of a transaction block: The stream will update with the tables modified in the transaction after it completes successfully. If the transaction fails, the stream will not update.
- streams created inside a transaction block: The stream will update for each write in the transaction. When the transaction completes, successful or not, streams created in it will close. Writes happening outside of this transaction will not affect the stream.
Please note that nested transactions are not supported. Creating another transaction inside a transaction returns the parent transaction.
See also:
- the docs on transactions
Implementation
Future<T> transaction<T>(Future<T> Function() action) async {
final resolved = resolvedEngine;
if (resolved is Transaction) {
return action();
}
return await resolved.doWhenOpened((executor) {
final transactionExecutor = executor.beginTransaction();
final transaction = Transaction(this, transactionExecutor);
return _runConnectionZoned(transaction, () async {
var success = false;
try {
final result = await action();
success = true;
return result;
} catch (e, s) {
await transactionExecutor.rollbackAfterException(e, s);
// pass the exception on to the one who called transaction()
rethrow;
} finally {
if (success) {
try {
await transaction.complete();
} catch (e, s) {
// Couldn't commit -> roll back then.
await transactionExecutor.rollbackAfterException(e, s);
rethrow;
}
}
await transaction.disposeChildStreams();
}
});
});
}