2012-04-11 14 views
10

Sto implementando un commit a 2 fasi che coinvolge risorse distribuite. Come faccio a simulare il fallimento di un database partecipante? Estrarre il cavo di rete non funziona perché provoca il deadlock del tavolo. Attualmente sto usando ganci nel mio codice applicazione che lanciano StaleConnectionException in diversi punti come prima dell'esecuzione della query, dopo l'esecuzione della query. La mia preoccupazione per questo approccio è:Come simulare l'errore del database per verificare il commit a 2 fasi in Java

  • Esiste un modo migliore per simulare l'errore del DB?
  • Cosa succede all'oggetto connessione quando la connessione DB va male? Conserva il suo valore o diventa nulla?
  • Cosa succede in realtà quando l'applicazione tenta di riconnettersi al DB? Che valore ottiene l'oggetto di connessione? Utilizza un valore esistente dal pool di connessioni?

desidero anche per testare in punti intermedi come durante l'esecuzione di query, durante commit (dopo preparare viene inviato, ecc). In questo momento metto l'applicazione in modalità di debug e passo alla chiamata di funzione e tiro la spina in mezzo. Ma questo approccio è manuale e non funzionerà per un test di scala.

C'è un simulatore/emulatore o strumento che può aiutarmi a fare questo?

+0

Stai mirando a un particolare database, o questa deve essere una soluzione generalizzata per qualsiasi database collegato a JDBC? – kgrittn

+0

sto usando DB2 e DB2 z/OS adesso. – Andy

+0

Andy, quale metodo per simulare l'errore del database hai scelto? – dmiandre

risposta

1

Probabilmente è possibile aggiungere la propria risorsa che parteciperà al commit e interromperà la transazione dopo la prima fase. Nel frattempo puoi "staccare la spina".

+0

Non posso aggiungere più risorse di quante ne abbia già disponibili. Inoltre non ho il controllo sulla loro esecuzione, non posso fermarmi e avviarli come sono DB DEV. – Andy

+0

Penso che ciò che intendeva Andrej sia quello di arruolare un altro XAResource (fittizio) che scatenerebbe un qualche tipo di errore tra preparare e commettere. Il modo corretto sarebbe quello di creare un adattatore di risorse. Si potrebbe anche provare ad integrare XAResource direttamente dall'applicazione, ma penso che WebSphere non lo consenta tramite le API JTA standard (si noti che normalmente ciò non è comunque consentito da J2EE). È necessario utilizzare un'API specifica di WebSphere (poiché WebSphere richiede all'utente di generare un cosiddetto "token di ripristino" quando si esegue l'integrazione di una XAResource). –

1

Andrej ha risposto a una parte della domanda, quindi rispondo alla seconda parte.

L'oggetto Connection che si ottiene nell'applicazione è solo un wrapper attorno alla connessione fisica. Questo wrapper svolge un ruolo nel pool di connessioni e nella gestione delle transazioni. Se qualcosa va storto con il DB, il wrapper di connessione diventa inutilizzabile e puoi solo eseguire il rollback. Questo ha senso perché si accede alla connessione solo prima dell'avvio del 2PC, e qualsiasi cosa fatta prima dell'inizio del 2PC non può essere recuperata.

Si noti che il tentativo di rilasciare la connessione e acquisirne uno nuovo non cambia nulla perché una volta che una connessione da una determinata origine dati è stata utilizzata in una transazione, si otterrà sempre la stessa connessione dall'origine dati per tanto tempo come sei nella stessa transazione. Ciò significa che l'applicazione non può "riconnettersi" senza riavviare l'intera transazione.

D'altra parte, se qualcosa va storto dopo che tutte le risorse sono state preparate ma prima che tutte le risorse siano state commesse, è responsabilità del gestore delle transazioni recuperare la transazione. Ma questo succede dietro la scena e la tua applicazione non ha controllo. Anche a questo punto, si prevede che la tua applicazione abbia rilasciato tutte le connessioni utilizzate in quella transazione.

+0

Thnx per spiegazioni in dettaglio. Quello che sta accadendo nel mio caso è: eseguo una query su entrambi i DB come parte della transazione, e proprio quando sta per commettere, tolgo la spina. L'applicazione genera una "javax.transaction.HeuristicMixedException" e quindi tenta di eseguire il rollback. Ora quando la TM (Websphere nel mio caso) tenta di eseguire il rollback, ottiene la seguente esecuzione: "XAException si è verificato Il codice di errore è: XAER_NOTA (-4) ERRORCODE = -4228, SQLSTATE = null". Quindi il mio qn è: Se il commit non è mai stato chiamato, la preparazione non è mai stata inviata. La TM continua a chiamare il rollback? – Andy

+0

Inoltre, il mio approccio al lancio di una "StaleConnectionException" è sufficiente per simulare un errore del DB o devo anche rilasciare le connessioni? – Andy

0

La soluzione migliore è probabilmente da utilizzare nei database di memoria. Richiama l'errore e controlla lo stato delle origini dati prima e dopo per assicurarti che il rollback/commit sia eseguito correttamente.

Per quanto riguarda gli altri dubbi, questi sembrano test di costo estremamente alto/basso. Leggi la documentazione dei tuoi fornitori e assicurati che il tuo ambiente di transazione sia configurato in modo appropriato. Uno di questi si dovrebbe probabilmente automatizzare così le sue mani.

A meno che non abbiate scritto il proprio gestore di transazioni 2PC specifico per gestore di transazioni + implementazione del DB, lascerei il test di queste funzionalità al vostro fornitore.

4

Ecco un sacco di domande :) Proverò a completare le risposte precedenti.

Is there a better way to simulate the DB failure? 

test tutti i casi è complicato. Un modo per testare i casi principali sarebbe quello di creare un connettore JCA (un driver DB è è un connettore JCA). È possibile ottenere connessioni dal connettore che verrà inserito nella transazione (un terzo partecipante). La connessione può quindi sollevare determinati errori.

Ci sono tre parti che lavorano insieme: (1) l'applicazione, (2) l'applicazione. gestore delle transazioni del server e (3) il connettore jca (cosiddetto adattatore risorse).

Communications between the three parts

collegamento stesso ganci nella transazione via ManagedConnection.getXAResource. Con un connettore JCA personalizzato è possibile quindi sollevare eccezione all'applicazione (Connection nel picutre) o gestore delle transazioni del server di applicazione (XAResource ottenuti tramite la ManagedConnection nell'immagine). È possibile eccezione in particolare tiro durante XAResource.prepare e XAResource.commit, che corrisponde a errori durante la fase 2 commesso.

Nota che è difficile per controllare l'ordine di enlisment dei partecipanti (vedi this question). Quindi è facile provare che uno dei prepare fallisce (vale a dire il tuo), ma è difficile controllare l'ordine in cui vengono chiamati. La riproduzione di tutti gli stati non validi di commit a 2 fasi è complicata, specialmente quando si utilizza l'ottimizzazione.

(ho scritto una volta un connettore JCA (http://code.google.com/p/txfs) e ci sono altri intorno, se si desidera che il codice di esempio.)

What happens to the connection object when DB connection goes bad? 
Does it retain its value or does it become null? 

Il ManagedConnection può notificare al gestore delle transazioni. Una delle notifiche è ConnectionEvent.CONNECTION_ERROR_OCCURRED che informa che si è verificato un errore durante l'utilizzo di questa particolare connessione.

Come osservato in altra risposta, v'è normalmente una connessione gestita associato per ogni transazione. La connessione gestita astrae la connessione fisica e non si desidera utilizzarne troppe. L'applicazione ottiene solo "maniglie" (Connection nella figura). Le maniglie ottenute all'interno di una determinata transazione puntano tutte alla stessa connessione gestita. Questa è un'ottimizzazione supportata dalla maggior parte dei server delle app.

Se la connessione gestita diventare non valida, le maniglie che lo utilizzano non sono più validi pure. Ma le maniglie non possono essere "rinfrescate" da AFAIK. La transazione deve essere ripristinata, la connessione gestita viene distrutta. All'avvio di un'altra transazione, questa verrà associata a un'altra connessione gestita valida dal pool.

What actually happens when application tries to reconnect to DB? 
What value does connection object get? 
Does it use an existing value from the connection pool? 

L'application server gestisce un pool di connessione gestita. Come detto nel paragrafo precedente, si potrebbe andare male mentre viene usato. Ma si può anche andare male senza essere usati. Ad esempio, una connessione gestita utilizzata nel pool potrebbe diventare non valida perché la connessione fisica sottostante è scaduta. I server di app hanno solitamente una funzione per verificare se una connessione gestita è valida, prima che inizi a utilizzarla.In caso contrario, tenterà un'altra connessione gestita dal pool o ne creerà una nuova.

+0

Grazie per una spiegazione così dettagliata. Non ho ancora avuto il tempo di testarlo. Voterò una volta che avrò modo di testarlo, ancora una volta con una spiegazione così dettagliata – Andy

+0

Spero che sia d'aiuto. Quello che vuoi fare non è facile. (E come ha scritto @ nsfyn55, c'è un "costo estremamente alto/bassa ricompensa") – ewernli