Transactions

Transactions guarantee that either all operations within the transaction are executed, or none are. They are useful for ensuring data consistency during complex operations.

The simplest way to use transactions looks like this:

$database->beginTransaction();
try {
	$database->query('DELETE FROM articles WHERE id = ?', $id);
	$database->query('INSERT INTO audit_log', [
		'article_id' => $id,
		'action' => 'delete'
	]);
	$database->commit();
} catch (\Exception $e) {
	$database->rollBack();
	throw $e;
}

You can achieve the same result much more elegantly using the transaction() method. It accepts a callback which is executed within the transaction. If the callback runs without an exception, the transaction is automatically committed. If an exception occurs, the transaction is rolled back, and the exception is propagated further.

$database->transaction(function ($database) use ($id) {
	$database->query('DELETE FROM articles WHERE id = ?', $id);
	$database->query('INSERT INTO audit_log', [
		'article_id' => $id,
		'action' => 'delete'
	]);
});

Calls to transaction() can be nested, which makes it easy to compose methods that each manage their own transaction. Only the outermost transaction is actually sent to the database as BEGIN/COMMIT; inner calls merely track the nesting depth. Calling beginTransaction(), commit(), or rollBack() manually inside a transaction() callback throws a LogicException.

The transaction() method can also return values:

$count = $database->transaction(function ($database) {
	$result = $database->query('UPDATE users SET active = ?', true);
	return $result->getRowCount(); // returns the number of updated rows
});
version: 4.x 3.x