This library implements nesting of transactions so code that uses transactions can be safely and arbitrarily composed.
There is a stack of in-progress transactions. Calling $txn = new Transaction(...)
adds a transaction to the top of the stack. Calling $txn->commit()
removes a transaction from the stack (and releases the savepoint). Calling $txn->rollback()
rolls back a transaction and all transactions above it on the stack.
The transaction at the bottom of the stack represents a real START TRANSACTION
/COMMIT
/ROLLBACK
. Transactions above the root transaction represent a SAVEPOINT ...
/ROLLBACK TO ...
/RELEASE SAVEPOINT ...
. Committing the root transaction does not COMMIT
until all transactions on the stack have been committed or rolled back.
Nothing happens when a Transaction
object falls out of scope. A transaction that is never committed or rolled back remains stuck on the stack and prevents the root transaction from committing. A Transaction
object which commits on __destruct()
if it hasn't already been committed or rolled back may be preferred.
The TransactionManager
class can be used directly or it can be delegated to from another object implementing ITransactionManager
(eg. a database connection class).
function foo(ITransactionManager $db) {
$txn = new Transaction($db);
// ...
blah($db);
// ...
if ($okay) {
$txn->commit();
} else {
$txn->rollbck();
}
}
function blah(ITransactionManager $db) {
$txn = new Transaction($db);
try {
// ...
} catch (\Exception $e) {
$txn->rollback();
throw $e;
}
$txn->commit();
}
foo(new TransactionManager(...));