Documentazione di PostgreSQL 9.0 > Tutorial > Caratteristiche Avanzate > Transazioni
PrecedenteChiavi EsterneFunzioni di FinestraSuccessivo

3.4. Transazioni

Le transazioni sono un concetto fondamentale in tutti i sistemi di database. Il punto essenziale di una transazione è che essa concentra diversi passi in una singola operazione "tutto-o-niente". Gli stati intermedi tra i diversi passi non sono visibili alle transazioni concorrenti, e se si verifica qualche errore che impedisce il completamento della transazione, nessuno dei passi completati va ad interessare il database.

Per esempio, considerare il database di una banca che contiene i saldi dei conti di diversi clienti, come pure i saldi dei depositi totali per settore. Supponiamo di voler registrare un pagamento di $100.00 dal conto di Alice al conto di Bob. Semplificando all'eccesso, il comando SQL per fare questo potrebbe essere:

UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
UPDATE branches SET balance = balance - 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Alice');
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';
UPDATE branches SET balance = balance + 100.00
    WHERE name = (SELECT branch_name FROM accounts WHERE name = 'Bob');

I dettagli di questi comandi non sono importanti; la cosa importante è che per realizzare questa operazione piuttosto semplice, sono necessari diversi aggiornamenti separati. I nostri funzionari di banca vorranno essere sicuri che ognuno di questi aggiornamenti si verifichi, o che non si verifichi nessuno di essi. Essi non vorrebbero certamente che, per un guasto di sistema, risultasse in Bob un accredito di $100.00 e nessun addebito nel conto di Alice. Mentre Alice non sarebbe una cliente felice se gli fossero stati addebitati $100.00 senza il corrispondente accredito nel conto di Bob. Abbiamo bisogno di una garanzia che se qualcosa va male all'interno dell'operazione, nessuno dei passi eseguiti abbia effetto. Raggruppando gli aggiornamenti in una transazione avremo questa garanzia. Una transazione si dice essere atomica: dal punto di vista di altre transazioni, se si attua completamente o per niente.

Si vuole anche una garanzia che una volta che una transazione è completata e riconosciuta dal sistema di database, essa sia permanentemente registrata e non vada persa, anche se subito dopo si verifica un arresto del sistema. Per esempio, se stiamo registrando un prelevamento di denaro effettuato da Bob, non vogliamo assolutamente che il debito di questo cliente sparisca per un blocco del sistema che si verifica dopo che il cliente è uscito dalla porta della banca. Un database transazionale garantisce che tutti gli aggiornamenti fatti tramite una transazione siano registrati su un supporto permanente (es., su disco) prima che venga segnalato il completamento della transazione.

Un altra importante proprietà dei database transazionali è strettamente collegata alla nozione di aggiornamenti atomici: quando diverse transazioni vengono eseguite concorrentemente, ognuna di esse non dovrebbe poter vedere i cambiamenti incompleti fatti dalle altre. Per esempio, se una transazione si sta occupando completamente di tutto il ramo saldi, essa non dovrebbe includere il debito dal ramo Alice e non il credito al ramo Bob, nè viceversa. Per cui le transazioni devono essere tutto-o-niente non solo per quanto riguarda il loro effetto permanente nel database, ma anche per quanto riguarda la loro visibilità. Gli aggiornamenti fatti da una transazione aperta sono invisibili alle altre transazioni finchè la transazione non è stata completata, dopodichè tutti gli aggiornamenti fatti diventano visibili contemporaneamente.

In PostgreSQL™, una transazione è impostata racchiudendo i comandi SQL della transazione tra i comandi BEgin e COMMIT. Per cui la nostra transazione bancaria assumerà questa forma:

BEgin;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
-- etc etc
COMMIT;

Se, durante l'elaborazione della transazione, si decide di non volerla completare (per esempio, se ci viene notificato che il conto di Alice è negativo), possiamo eseguire il comando di rinuncia ROLLBACK invece del comando di conferma COMMIT, e tutti gli aggiornamenti eseguiti fino a quel momento saranno cancellati.

PostgreSQL™ attualmente tratta ogni istruzione SQL come se fosse eseguita dentro una transazione. Se non date un comando BEgin, ogni istruzione individuale verrà racchiusa tra un implicito BEgin e (se riuscita) un COMMIT. Un gruppo di istruzioni racchiuse tra BEgin e COMMIT viene talvolta chiamato blocco di transazione.

[Nota]

Nota

Alcune librerie client impartiscono i comandi BEgin e COMMIT automaticamente, per cui si ottiene l'effetto blocco di transazione senza averlo richiesto. Controllare la documentazione per l'interfaccia che state utilizzando.

È possibile controllare le istruzioni in una transazione in modo granulare tramite l'utilizzo di savepoint. I savepoint vi consentono di scartare selettivamente parti della transazione, confermando il resto. Dopo aver definito un savepoint con SAVEPOINT, potrete tornare indietro al savepoint con ROLLBACK TO. Tutte le modifiche al database poste tra la definizione del savepoint ed il ritorno ad esso vengono scartate, mentre le modifiche precedenti il savepoint sono mantenute.

Dopo essere tornati indietro ad un savepoint, lo stesso continua ad essere definito, per cui potrete tornare indietro ad esso diverse volte. Al contrario, se siete sicuri di non voler tornare ancora indietro ad un particolare savepoint, esso può essere rilasciato, in modo che il sitema possa liberare alcune risorse. Ricordatevi che sia il rilascio che il tornare indietro ad un savepoint rilascerà automaticamente tutti i savepoint che sono definiti dopo di esso.

Tutto questo si verifica dentro il blocco di transazione, così niente di questo sarà visibile alle altre sessioni del database. Quando e se il blocco di transazione termina con commit, le azioni confermate diventano visibili come una unità alle altre sessioni, mentre le azioni rolled-back non verranno viste per niente.

Ricordando il database della banca, si supponga di dover addebitare $100.00 dal conto di Alice, ed accreditarle nel conto di Bob, per scoprire solo più tardi che si doveva accreditarli sul conto di Wally. È possibile rimediare usando un savepoint come questo:

BEgin;
UPDATE accounts SET balance = balance - 100.00
    WHERE name = 'Alice';
SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Bob';
-- oops ... forget that and use Wally's account
ROLLBACK TO my_savepoint;
UPDATE accounts SET balance = balance + 100.00
    WHERE name = 'Wally';
COMMIT;

Questo esempio, naturalmente, è enormemente semplificato, ma comprende il controllo effettuato tramite savepoint dentro un blocco di transazione. Inoltre, ROLLBACK TO è il solo modo per riprendere il controllo di un blocco di transazione abortito dal sistema a causa di un errore, scorciatoia che ci consente di non dover tornare indietro completamente e ripartire di nuovo.

Documentazione di PostgreSQL 9.0 > Tutorial > Caratteristiche Avanzate > Transazioni
PrecedenteChiavi EsterneFunzioni di FinestraSuccessivo