Transakce
Transakce zaručují, že se buď provedou všechny operace v rámci transakce, nebo se neprovede žádná. Jsou užitečné pro zajištění konzistence dat při složitějších operacích.
Základní použití
Nejjednodušší způsob použití transakcí vypadá takto:
$db->beginTransaction();
try {
$db->query('DELETE FROM articles WHERE id = ?', $id);
$db->query('INSERT INTO audit_log', [
'article_id' => $id,
'action' => 'delete'
]);
$db->commit();
} catch (\Exception $e) {
$db->rollBack();
throw $e;
}
Mnohem elegantněji můžete to samé zapsat pomocí metody transaction()
:
$db->transaction(function ($db) use ($id) {
$db->query('DELETE FROM articles WHERE id = ?', $id);
$db->query('INSERT INTO audit_log', [
'article_id' => $id,
'action' => 'delete'
]);
});
Metoda transaction()
může také vracet hodnoty:
$count = $db->transaction(function ($db) {
$result = $db->query('UPDATE users SET active = ?', true);
return $result->getRowCount(); // vrátí počet aktualizovaných řádků
});
Zanořené transakce
Nette Database podporuje zanořování transakcí pomocí SQL savepointů. To znamená, že můžete spustit transakci uvnitř jiné transakce. Zde je jednoduchý příklad:
$db->transaction(function ($db) {
// hlavní transakce
$db->query('INSERT INTO users', ['name' => 'John']);
// vnořená transakce
$db->transaction(function ($db) {
$db->query('UPDATE users SET role = ?', 'admin');
// pokud zde nastane chyba, vrátí se zpět jen vnořená transakce
// hlavní transakce pokračuje dál
});
// pokračování hlavní transakce
$db->query('INSERT INTO user_log', ['action' => 'user created']);
});
Podkladový mechanismus využívá ve skutečnosti jen jednu transakci na úrovni databáze a vnořené transakce emuluje pomocí savepointů. Toto chování je stejné pro všechny databáze a je zcela transparentní.
Auto-commit režim
Auto-commit určuje, zda se každý dotaz automaticky provede v samostatné transakci. Ve výchozím nastavení je auto-commit zapnutý, což znamená, že každý dotaz tvoří samostatnou transakci.
Auto-commit můžete vypnout v konfiguraci:
database:
dsn: 'mysql:host=127.0.0.1;dbname=test'
user: root
password: secret
options:
autoCommit: false # vypne auto-commit
nebo v kódu:
$db->setAutoCommit(false);
Při vypnutém auto-commitu se automaticky spustí nová transakce v těchto případech:
- při připojení k databázi
- po dokončení předchozí transakce (commit nebo rollback)
Pokud změníte nastavení auto-commitu během aktivní transakce, transakce se automaticky potvrdí.