Transazioni a metà: quando un rollback mancato corrompe i tuoi dati

VibeInspect.ai · 25 agosto 2026 · 5 min di lettura
- transazioni
- database
- cursor
- audit
- rollback
Un errore intercettato può lasciare scritture parziali nel tuo database
Una guida tecnica pubblicata su dev.to, Database Transaction Management in ColdFusion, racconta un problema che va ben oltre ColdFusion: quando gestisci una transazione e un blocco try/catch intercetta l'eccezione, il rollback automatico non parte più. Il risultato è brutale nella sua semplicità: una parte delle scritture resta salvata, l'altra no, e il database rimane in uno stato incoerente.
La frase chiave della fonte è netta: un errore catturato "can leave a partial write committed unless you explicitly call rollback in the catch". Tradotto in pratica: se pensavi che la transazione ti proteggesse in automatico, ti sbagliavi. Ti protegge solo se il rollback viene invocato davvero.
Questo non è un dettaglio di un linguaggio di nicchia. È un pattern che si ripete ovunque ci siano transazioni, gestione degli errori e concorrenza. E se il tuo codice l'ha scritto un assistente AI, è esattamente il tipo di trappola che passa inosservata.
Cosa significa se il tuo codice l'ha scritto Cursor
Quando chiedi a Cursor di implementare un flusso che tocca più tabelle — un ordine con relativo pagamento e aggiornamento dello stock, per fare un esempio — l'assistente produce codice che sembra corretto. Apre una transazione, esegue le query, chiude. In superficie funziona: i test manuali passano, la demo gira, il primo utente non nota nulla.
Il problema è la gestione degli errori. Molti frammenti generati avvolgono la logica in un blocco try/catch per "non far crashare l'app". Ma se quel catch inghiotte l'eccezione senza far scattare il rollback, hai costruito una bomba a orologeria. Alla prima query che fallisce a metà — un vincolo violato, un timeout, un deadlock — parte delle scritture resta salvata e parte sparisce.
Non lo scopri subito. Lo scopri settimane dopo, quando un cliente ha pagato ma l'ordine non risulta, oppure lo stock è stato scalato per una vendita mai registrata. A quel punto non hai un bug: hai dati corrotti, e i dati corrotti non si correggono con un deploy.
Lo stesso vale per i deadlock citati nella fonte: transazioni concorrenti che bloccano le stesse righe in ordine diverso. Cursor difficilmente ragiona sull'ordine di accesso alle tabelle o sui livelli di isolamento, perché non vede il carico reale del tuo sistema. Genera codice che funziona con un utente e collassa con cento.
Perché ora ti serve un audit
Il motivo per cui questi problemi sopravvivono al lancio è semplice: nessuno ha mai dato un verdetto sul codice. Hai sviluppato in fretta, hai pubblicato, e il repository è passato dallo stato "prototipo" allo stato "produzione" senza che qualcuno si fermasse a chiedersi cosa succede quando le cose vanno storte.
Un audit serve proprio a questo: a rispondere alla domanda "in che stato è davvero il mio codice quando gestisce transazioni, errori e concorrenza?". Non è una questione di stile o di eleganza. È una questione di integrità dei dati, che è la cosa più difficile da recuperare quando si rompe.
VibeInspect affronta esattamente questo scenario. Carichi lo ZIP del repository, gli specialisti AI analizzano il codice e ricevi un PDF con il verdetto. Nessun server da configurare, e il codice sorgente viene cancellato al termine dell'analisi. Non è un pentest e non corregge il codice al posto tuo: ti dice dove sono i punti in cui una transazione può lasciare scritture parziali, dove manca il rollback, dove l'ordine di accesso alle tabelle rischia un deadlock.
Con il piano Diagnostic ottieni file, riga ed evidenze: sai esattamente quale blocco catch sta silenziando l'eccezione che avrebbe dovuto far ripartire il rollback. È la differenza tra sapere che "forse c'è un problema" e sapere che "nel file checkout, riga 84, l'errore viene intercettato ma la transazione non viene annullata".
Cosa un linter non vede
Qui sta il punto che confonde molti. "Ma io ho già ESLint, ho già i controlli automatici." Un linter è utile, ma guarda la forma del codice, non il suo comportamento a runtime.
Un linter ti segnala una variabile non usata, un import mancante, una formattazione incoerente. Non ti dirà mai che il tuo blocco catch, sintatticamente perfetto, sta impedendo il rollback di una transazione. Non capisce la semantica di "cosa succede ai dati se questa query fallisce a metà".
Allo stesso modo, un linter non ha idea dell'ordine con cui accedi alle tabelle in transazioni diverse, quindi non può prevedere un deadlock. Non conosce il livello di isolamento che hai scelto, non sa se stai usando SERIALIZABLE dove basterebbe READ COMMITTED, non valuta se la transazione è troppo lunga e tiene lock troppo a lungo.
Tutte queste sono decisioni logiche, non stilistiche. Sono il genere di cosa che un linter salta e che un audit di comportamento evidenzia. Il codice generato dall'AI passa quasi sempre il linter: è pulito, ordinato, ben formattato. Il problema non è la forma. È cosa fa quando qualcosa va storto.
Cosa fare questa settimana
Non serve riscrivere tutto. Serve un controllo mirato, e puoi farlo in pochi passi:
- Individua ogni transazione nel repository. Cerca dove apri e chiudi transazioni verso il database e segna quali flussi toccano più tabelle contemporaneamente.
- Controlla ogni try/catch che avvolge una transazione. Chiediti: se questa query fallisce, il rollback parte davvero? O l'errore viene silenziato e le scritture precedenti restano?
- Verifica l'ordine di accesso alle tabelle. Se due flussi diversi bloccano le stesse righe in ordine opposto, hai un rischio deadlock concreto.
- Riguarda i livelli di isolamento. Stai usando SERIALIZABLE dove basterebbe READ COMMITTED? Stai tenendo transazioni aperte più del necessario?
Se non hai il tempo o la certezza per fare questa verifica a mano — e con un repository costruito in fretta con l'AI è normale non averla — lascia che sia un audit a darti il verdetto. Carica lo ZIP su VibeInspect e con il piano Diagnostic ottieni file, riga ed evidenze dei punti dove una transazione può lasciarti con dati a metà.
Aver usato Cursor non è il problema. Il problema è pubblicare senza sapere cosa succede ai tuoi dati quando una query fallisce. Questa settimana, scioglilo.
Domande frequenti
Perché una transazione può lasciare scritture parziali?
Se un errore viene intercettato da un blocco try/catch senza invocare esplicitamente il rollback, il rollback automatico non scatta. Parte delle query resta salvata e parte no, lasciando il database in uno stato incoerente.
Un linter rileva questi problemi?
No. Un linter analizza la forma del codice: variabili, import, formattazione. Non valuta il comportamento a runtime, quindi non vede un rollback mancante, un ordine di accesso alle tabelle che genera deadlock o un livello di isolamento sbagliato.
VibeInspect corregge il codice al posto mio?
No. VibeInspect non corregge il codice, non è un pentest e non garantisce sicurezza assoluta. Ti fornisce un verdetto: con il piano Diagnostic ricevi file, riga ed evidenze dei punti critici, così sai esattamente dove intervenire.
Il mio codice sorgente resta al sicuro?
Sì. Carichi lo ZIP del repository, l'analisi gira senza che tu debba configurare server e il codice sorgente viene cancellato al termine dell'analisi.
Quale piano scelgo per un problema di transazioni?
Il piano Diagnostic (€499), perché affronti un problema tecnico specifico e ti serve sapere file, riga ed evidenze. Lo Snapshot (€49) dà solo score e verdetto generale, senza indicazioni di file o riga.