Per molto tempo, ho utilizzato un complicato sistema di controlli per poter utilizzare le transazioni del database. La logica delle transazioni è la seguente: aprire una transazione, eseguire le operazioni del database, eseguire il rollback in caso di errore o eseguire il commit in caso di successo. La complicazione deriva da ciò che accade quando si desidera eseguire un'operazione aggiuntiva all'interno della stessa transazione. Dovresti scrivere un secondo metodo che esegue entrambe le operazioni oppure puoi chiamare il tuo metodo originale da un secondo, aprendo una transazione solo se non ne è già stato aperto uno e non hai eseguito il commit / rollback delle modifiche solo se tu fossi il uno per aprire la transazione.
Ad esempio:
public void method1() {
boolean selfOpened = false;
if(!transaction.isOpen()) {
selfOpened = true;
transaction.open();
}
try {
performDbOperations();
method2();
if(selfOpened)
transaction.commit();
} catch (SQLException e) {
if(selfOpened)
transaction.rollback();
throw e;
}
}
public void method2() {
boolean selfOpened = false;
if(!transaction.isOpen()) {
selfOpened = true;
transaction.open();
}
try {
performMoreDbOperations();
if(selfOpened)
transaction.commit();
} catch (SQLException e) {
if(selfOpened)
transaction.rollback();
throw e;
}
}
Si noti che non sto sostenendo il codice sopra con alcun mezzo. Questo dovrebbe servire da esempio di cosa non fare!
Sembrava sciocco creare un secondo metodo per eseguire la stessa logica del primo e qualcosa in più, tuttavia volevo essere in grado di chiamare la sezione API del database del programma e risolvere i problemi lì. Tuttavia, mentre questo risolve parzialmente il mio problema, ogni metodo che ho scritto implicava l'aggiunta di questa logica verbosa per verificare se una transazione è già aperta e per eseguire il commit / rollback delle modifiche se il mio metodo l'ha aperto.
Il problema era concettuale. Non avrei dovuto tentare di abbracciare ogni possibile scenario. L'approccio corretto era quello di ospitare la logica di transazione in un singolo metodo prendendo un secondo metodo come parametro che avrebbe eseguito la logica del database reale. Quella logica assume la transazione è aperta e non esegue nemmeno un controllo. Questi metodi potrebbero essere chiamati in combinazione in modo che questi metodi non fossero ingombri di una logica di transazione non necessaria.
La ragione per cui lo dico è che il mio errore è stato supporre che dovevo far funzionare il mio metodo in qualsiasi situazione. In tal modo, non solo il mio metodo chiamato verificava se una transazione era aperta, ma anche quelli che chiamava. In questo caso, non è un grande successo di prestazioni, ma se per esempio dovevo verificare l'esistenza di un record nel database prima di procedere, dovrei controllare per ogni metodo che lo richiede quando avrei dovuto presupporre che il chiamante dovrebbe essere informato che il record dovrebbe esistere. Se il metodo viene chiamato comunque, si tratta di un comportamento indefinito e non è necessario preoccuparsi di ciò che accade.
Piuttosto, dovresti fornire molta documentazione e scrivere ciò che ritieni sia vero prima che venga effettuata una chiamata al tuo metodo. Se è abbastanza importante, aggiungilo come commento prima del tuo metodo in modo che non ci siano errori (javadoc fornisce un buon supporto per questo genere di cose in java).
Spero che ti aiuti!