2009-07-23 12 views
7

Ho problemi con un aggiornamento Oracle. La chiamata a ExecuteNonQuery si blocca indefinitamente.Oracle Update Hangs

Il codice:

using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn)) 
{ 
    foreach (string colName in dbData.Values.Keys) 
     cmd.Parameters.Add(colName, dbData.Values[colName]); 

    cmd.CommandTimeout = txTimeout; 
    int nRowsAffected = cmd.ExecuteNonQuery(); 
} 

CommandTimeout viene impostato a 5, ed i parametri vengono impostati su valori interi piccoli.

La query:

UPDATE "BEN"."TABLE03" SET "COLUMN03"=:1,"COLUMN04"=:2 WHERE COLUMN05 > 0 

La query viene eseguita rapidamente da sqlplus, e normalmente corre veloce dal mio codice, ma ogni tanto si blocca sempre.

Ho eseguito una query su v $ locked_object e c'è un record che si riferisce a questa tabella, ma penso che sia l'aggiornamento che non sta completando.

Ci sono due cose che vorrei sapere: cosa potrebbe causare l'interruzione dell'aggiornamento?

Ancora più importante, perché non viene lanciata un'eccezione qui? Mi aspetterei che la chiamata attenda cinque secondi, quindi scada.

+0

Quale versione di Oracle? Può eseguire questa query: "seleziona * da v $ version" e copia la riga 1. Dovrebbe apparire come: "Oracle Database 10g Release 10.2.0.4.0 - Produzione". Inoltre, questa è una vera tabella o una vista con invece di trigger? Ha dei trigger prima/dopo? –

risposta

5

Quando un semplice aggiornamento si blocca spesso significa che si è bloccati da un'altra sessione. Oracle non consentirà più di una transazione per aggiornare una riga. Fino a quando una transazione non ha eseguito il commit o il rollback delle sue modifiche bloccherà le righe che ha aggiornato/cancellato. Ciò significa che un'altra sessione dovrà attendere se desidera modificare le stesse righe.

È necessario SELEZIONARE ... PER AGGIORNARE NOWAIT prima di AGGIORNARE se non si desidera bloccare indefinitamente.

+0

+1, particolarmente vero per gli hang sporadici. – DCookie

0

sembra che il database sia in attesa di un commit/rollback in modo da bloccare la riga. Vorrei suggerire di aggiungere

int nRowsAffected = cmd.ExecuteNonQuery(); 
cmd.Commit(); 
2

Si può vedere quale evento la sessione è in attesa su interrogando V $ session_wait (dopo aver individuato il SID della sessione, probabilmente, cercando in V $ SESSION). Se l'evento è simile a "accoda", stai aspettando un blocco tenuto da un'altra sessione, che in questo caso sembra una spiegazione probabile.

19

Sto sbattendo questo a causa del suo rango di pagina nei risultati di ricerca.

Nel mio caso, era perché avevo eseguito una query in SqlPlus, ma ho dimenticato di eseguirlo. In questo caso, è stato come ha dichiarato Vincent: la riga è stata bloccata in un'altra sessione.

Il commit dell'aggiornamento SqlPlus ha risolto il problema.

+3

Grazie, è stato molto utile. Ho fatto la stessa cosa ... – stoj

+1

esattamente quello che è successo a me. non appena ho eseguito il 'rollback' in SQLPlus, è tornato. –

+0

lifesaver - 4 anni dopo! – jasonscript

0

Ho riscontrato spesso questo problema e non solo le query di aggiornamento (in particolare le query "INSERT INTO ... SELECT FROM"). Questo è su Oracle 9i.

ho trovato la soluzione, così ha deciso di trovare questo correlate, al fine argomento: Nella stringa di connessione, impostare:

Pooling=False 

nella stringa di connessione. A, lavorando stringa completa di connessione potrebbe essere simile:

DATA SOURCE=k19.MYDOMAIN.com/plldb;PERSIST SECURITY INFO=True;Pooling=False;USER ID=IT;Password=SECRET 

Avvertenze: Impostazione pooling a false richiederà la query fissare una nuova connessione ogni volta che viene eseguito. Le query eseguite molto frequentemente potrebbero subire una riduzione delle prestazioni rispetto a quelle che avrebbero se ODP.NET fosse affidabile. Considerando il problema, correre un po 'più lentamente è molto meglio che appendere.

4

Stavo riscontrando un problema simile causato da un comando Sql che non era stato eseguito: credo che il programma si sia arrestato nel bel mezzo di uno ad un certo punto.

Ecco come ho risolto il mio problema:

In primo luogo, sqlplus aperta e fare un impegno a risolvere il problema.

Quindi, modificare il codice per confermare la transazione o il rollback se si verifica un'eccezione. Ciò manterrà il problema di nuovo.

Si potrebbe modificare il codice per qualcosa di simile:

using (OracleTransaction transaction = conn.BeginTransaction()) 
{ 
    using (OracleCommand cmd = new OracleCommand(dbData.SqlCommandStr, conn)) 
    { 
     foreach (string colName in dbData.Values.Keys) 
      cmd.Parameters.Add(colName, dbData.Values[colName]); 

     cmd.CommandTimeout = txTimeout; 

     try 
     { 
      int nRowsAffected = cmd.ExecuteNonQuery(); 
      transaction.Commit(); 
     } 
     catch 
     { 
      transaction.Rollback(); 
     } 
    } 
}