Domanda

Devo eseguire una selezione e quindi aggiornare alcune delle righe nel ResultSet in modo atomico.

Il codice che sto usando sembra (semplificato):

stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT ...");

while (rs.next()) {
    if (conditions_to_update) {
        rs.updateString(...);
        rs.updateRow();
    }
}
  • Posso garantire che gli aggiornamenti verranno eseguiti atomicamente? In caso contrario, come posso assicurarlo?
  • Cosa succede se qualsiasi altro processo ha modificato la riga del database che si sta aggiornando tramite updateRow () ? Esiste un modo per bloccare le righe nel ResultSet ?
È stato utile?

Soluzione

Probabilmente c'è un mucchio di tecnologie e concetti che entrano in gioco qui, e le cose iniziano a diventare piuttosto appiccicose quando inizi a considerare applicazioni multi-thread / multi-richiesta.

Come affermato da Iassevk, dovresti esaminare Transactions per garantire la natura atomica dei tuoi aggiornamenti - un esempio di livello molto basso sarebbe quello di fare qualcosa sulla falsariga di:

...
con.setAutoCommit(false);
try {
  while (rs.next()) {
    if (conditions_to_update) {
      rs.updateString(...);
      rs.updateRow();
    }
  }
  con.setAutoCommit(true);
} catch (Exception ex) {
  //log the exception and rollback
  con.rollback();
} finally {
  con.close();
}

Tutti gli aggiornamenti verrebbero quindi inseriti nella stessa transazione. Se uno degli aggiornamenti generasse un'eccezione (come un valore non valido o la connessione non riuscita a metà dei risultati), l'intero lotto verrebbe ripristinato. (Infine aggiunto perché ne sono un campione; p)

Questo, tuttavia, non risolverà il tuo secondo problema, ovvero due metodi concorrenti che tentano di aggiornare la stessa tabella: una condizione di competizione. Ci sono, secondo me, due approcci principali qui: ognuno ha i suoi pregi e i suoi svantaggi.

L'approccio più semplice sarebbe quello di Bloccare la tabella : ciò richiederebbe modifiche minime al codice ma presenta un inconveniente piuttosto grande. Partendo dal presupposto che, come con la maggior parte delle applicazioni, si legge di più che scrivere: il blocco della tabella impedirà a tutti gli altri utenti di visualizzare i dati, con la probabilità che il codice si blocchi, in attesa del rilascio del blocco prima del timeout della connessione entra e genera un'eccezione.

L'approccio più complesso è garantire che i metodi per eseguire questi aggiornamenti siano implementati in modo thread-safe. A tal fine:

  • Tutti gli aggiornamenti per questa tabella passano attraverso una singola classe
  • Quella classe implementa un modello Singleton o espone i metodi di aggiornamento come metodi statici
  • I metodi di aggiornamento utilizzano la parola chiave sincronizzata per prevenire le condizioni di gara

Altri suggerimenti

Usa transazioni.

  

Cosa succede se qualsiasi altro processo ha modificato la riga del database che si sta aggiornando tramite updateRow ()? Esiste un modo per bloccare le righe nel ResultSet?

In Oracle, è possibile contrassegnare alcune righe per l'aggiornamento emettendo il seguente SQL.

select cola, colB from tabA for update;

La prossima transazione / thread / app che tenta di aggiornare questa riga riceverà un'eccezione. vedere questo per maggiori dettagli - http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4530093713805

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top