Database Transaction
A database transaction is a sequence of operations performed as a single, logical unit of work. Transactions ensure data consistency and integrity by adhering to the ACID (Atomicity, Consistency, Isolation, Durability) properties. If any operation in the sequence fails, the transaction can be rolled back to its previous state.
Basics
<?php
$dbDriver = \ByJG\AnyDataset\Db\Factory::getDbInstance('mysql://username:password@host/database');
$dbDriver->beginTransaction(\ByJG\AnyDataset\Db\IsolationLevelEnum::SERIALIZABLE);
try {
// ... Perform your queries
$dbDriver->commitTransaction(); // or rollbackTransaction()
} catch (\Exception $ex) {
$dbDriver->rollbackTransaction();
throw $ex;
}
Nested Transactions
Nested transactions allow you to manage transactions within different functions or methods.
To enable nested transactions, pass the allowJoin
parameter as true
to the beginTransaction
method in all nested
transactions.
Two-Phase Commit
Nested transactions use a "Two-Phase Commit" process to ensure consistency:
- The transaction is only committed when all participants successfully commit.
- If any participant rolls back, all participants will roll back.
Important Points:
- The nested transaction must use the same
IsolationLevel
as the parent transaction; otherwise, it will fail. - All participants in the transaction must share the same instance of the
DbDriver
object. Using different instances, even with the same connection URI, can result in unpredictable behavior.
Example of Nested Transactions
<?php
use ByJG\AnyDataset\Db\IsolationLevelEnum;
use \ByJG\AnyDataset\Db\DbDriverInterface;
function mainFunction(DbDriverInterface $dbDriver)
{
$dbDriver->beginTransaction(IsolationLevelEnum::SERIALIZABLE);
try {
// ... Do your queries
nestedFunction($dbDriver);
$dbDriver->commitTransaction();
} catch (\Exception $ex) {
$dbDriver->rollbackTransaction();
throw $ex;
}
}
function nestedFunction(DbDriverInterface $dbDriver)
{
$dbDriver->beginTransaction(IsolationLevelEnum::SERIALIZABLE, allowJoin: true);
try {
// ... Do your queries
$dbDriver->commitTransaction();
} catch (\Exception $ex) {
$dbDriver->rollbackTransaction();
throw $ex;
}
}
# Call the main transaction
mainFunction($dbDriver);
Explanation:
- The
mainFunction
starts a transaction and performs some queries. - It calls
nestedFunction
. - The
nestedFunction
starts a nested transaction withallowJoin
set totrue
. - The
nestedFunction
commits its transaction, but the database commit is deferred until themainFunction
commits. - The
mainFunction
commits the transaction. - The entire transaction is committed to the database.
Good Practices When Using Transactions
- Always use a
try/catch
block: This ensures exceptions are handled, and transactions are rolled back in case of errors. - Commit or rollback in the same method: The transaction must be finalized (committed or rolled back) within the same method where it started. Never finalize it in a different method.
- Enable
allowJoin
for nested transactions: Use the allowJoin parameter as true in the beginTransaction method when nesting transactions.