Lavorando con i database spesso ci troviamo nella situazione di dover eseguire più query sequenzialmente con la certezza di essere sempre in una situazione consistente, ovvero o tutte le operazioni vengono eseguite oppure non ne deve essere eseguita nessuna riportando il database allo stato precedente.
A questo proposito PDO permette di gestire le transazioni, tuttavia sarà bene ricordare che potrebbero presentarsi dei limiti dovuti al database di riferimento, sarà quindi opportuno verificare tramite la documentazione che il database e la versione in uso supportino effettivamente tale funzionalità.
beginTransaction
Un primo feedback di controllo possiamo ottenerlo tramite PDO, quando andiamo ad iniziare la transizione; infatti il metodo beginTransaction()
restituirà false qualora il driver di riferimento appartenga ad un database che non supporta le transazioni.
Supponendo di avere la nostra solita connessione a disposizione, possiamo avviare la transazione in questo modo:
try {
$db = new PDO('mysql:host=localhost;dbname=corso', $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Errore: " . $e->getMessage();
die();
}
$db->beginTransaction();
Meglio ancora sarebbe inserire la transaction all'interno di un costrutto try catch
:
try {
$db->beginTransaction();
...
} catch (PDOException $e) {
$db->rollBack();
echo $e->getMessage();
}
Rollback
Nel caso in cui venga generata un'eccezione da beginTransaction()
, try catch
permette di procedere con il rollback
dell'operazione annullando tutte le query eseguite dopo la chiamata al metodo.
Vediamo quindi come gestire e rendere effettive le query dopo beginTransaction()
supponendo di dover effettuare un inserimento multiplo sulla nostra tabella degli utenti:
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome1', 'cognome1') ");
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome2', 'cognome2') ");
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome3', 'cognome3') ");
Commit
Il commit che renderà effettivi gli inserimenti nel database:
$db->commit();
Quindi abbiamo sostanzialmente un processo organizzato nei seguenti passaggi:
- connessione del database e setup degli errori come eccezioni;
- avvio della transazione;
- esecuzione delle query.
A questo punto, se tutto è andato come previsto, le query vengono "committate" e rese definitive, in alternativa se si è generata un'eccezione e tutte le query all'interno del blocco beginTransaction
vengono annullate, ripristinando la situazione precedente all'avvio della transazione.
Ecco il codice completo:
try {
$db = new PDO('mysql:host=localhost;dbname=corso_2016', $user, $pass);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Errore: " . $e->getMessage();
die();
}
try {
$db->beginTransaction();
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome1', 'cognome1') ");
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome2', 'cognome2') ");
$db->exec("INSERT INTO utenti(nome, cognome) VALUES('nome3', 'cognome3') ");
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
echo $e->getMessage();
}