2013-06-09 26 views
10

Ho una lunga lista di stringhe INSERT INTO .... Attualmente li corro con:Invio di numerosi comandi SQL in una singola transazione

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 
    foreach (var commandString in sqlCommandList) 
    { 
     SqlCommand command = new SqlCommand(commandString, connection); 
     command.ExecuteNonQuery(); 
    } 
} 

vedo che ogni ExecuteNonQuery() esegue anche commesso.

  1. C'è un modo per inserire tutte le righe in una singola transazione (commit alla fine)?
  2. Il motivo per cui desidero una singola transazione è rendere il processo di "inserimento" più veloce. Una singola transazione renderà anche più veloce?
+2

SQlBulkCopy http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx –

+0

è possibile utilizzare un ambito di transazione (fare riferimento a MSDN). – TGlatzer

+0

È possibile utilizzare il parallelismo per ogni –

risposta

-1

È possibile utilizzare in parallelo per ogni

using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     List<string> sqlCommandList = new List<string>(); 
     connection.Open(); 
     Parallel.ForEach(sqlCommandList, commandString => 
     { 
      SqlCommand command = new SqlCommand(commandString, connection); 
      command.ExecuteNonQuery(); 
     }); 
    } 
+3

1. parallel.foreach carica ogni transazione su un thread diverso (ogni thread terminerà con un commit e quindi ci sarà la stessa quantità di commit). 2. Ho provato, ma ho avuto un problema con l'ordine degli inserti. alcuni inserti si sono verificati prima dell'altro e hanno rotto la mia restrizione di chiave esterna. Ma grazie :-) – Jeb

27

La sua consiglia di utilizzare la transazione SQL nel caso in cui si sta eseguendo Query multiple in un thread, si può avere in questo modo:

SqlTransaction trans; 

    try 
    { 
     SqlConnection connection = new SqlConnection(connectionString); 
     connection.Open(); 

     trans = connection.BeginTransaction(); 

     foreach (var commandString in sqlCommandList) 
     { 
      SqlCommand command = new SqlCommand(commandString, connection,trans); 
      command.ExecuteNonQuery(); 
     } 

     trans.Commit(); 
    } 
    catch (Exception ex) //error occurred 
    { 
     trans.Rollback(); 
     //Handel error 
    } 
+0

"ExecuteNonQuery richiede che il comando abbia una transazione quando la connessione assegnata al comando è in una transazione locale in sospeso.La proprietà Transaction del comando non è stata inizializzata." – Fandango68

+2

@ Fernando68 >>> Comando SqlCommand = new SqlCommand (commandString, connection, trans); –

+0

Non dimenticare di disporre gli oggetti SqlTransaction e SqlConnection quando hai finito di usarli. – Sal

4

Potresti ottenere alcune prestazioni utilizzando solo una singola transazione e un comando, come indicato di seguito:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    try 
    { 
     connection.Open(); 

     using (SqlTransaction trans = connection.BeginTransaction()) 
     { 
      using (SqlCommand command = new SqlCommand("", connection,trans)) 
      { 
      command.CommandType = System.Data.CommandType.Text; 

      foreach (var commandString in sqlCommandList) 
      { 
       command.CommandText = commandString; 
       command.ExecuteNonQuery(); 
      } 
      } 

      trans.Commit(); 
     }   
    } 
    catch (Exception ex) //error occurred 
    { 
     //Handel error 
    } 
} 
+1

Metterei la riga 'command.ExecuteNonQuery();' nel proprio blocco 'try catch', così potrei chiamare' trans.Rollback(); 'esplicitamente se si è verificato un errore. Questo è il modo in cui i documenti MS lo mostrano, in ogni caso. –

+6

@Tony Non è necessario chiamare trans.rollback. L'oggetto SqlTransaction eseguirà il rollback nel suo metodo Dispose() se non è stato eseguito il commit esplicito (ad esempio se viene generata un'eccezione). Vedere la discussione seguente: [Perché utilizzare un'istruzione using con una SqlTransaction?] (Http: // StackOverflow.it/questions/1127830/why-use-a-using-statement-with-a-sqltransaction) –

+1

@Gerardo H - Tuttavia, se lo chiami esplicitamente, 1) sei sicuro che è fatto dovrebbe 'Smaltare' mai smettere di chiamare rollback per te, 2) è chiaro allo sviluppatore successivo quando si verifica un rollback. 3) Il blocco catch può anche consentire alcuni specifici errori di registrazione. Se quelli lo fanno valere la confusione extra varierà caso per caso. L'ho usato in entrambi i modi. – xr280xr

0

Un po 'in ritardo, ma se si inseriscono tutti i valori nella stessa tabella, codificare l'inserto SQL come "inserisci nei valori tablex (f1, f2, f3, ...) (@ F1, @ F2, @ F3 ...)". Creare il comando e aggiungere i parametri @ F1 ..., quindi impostare il flag Prepara sul comando. Ora mentre si scorre l'elenco dei valori da inserire, è possibile impostarli nei parametri appropriati e quindi eseguire ExecuteNonQuery. SQL analizzerà una volta la stringa di comando, quindi utilizzerà ogni volta i nuovi parametri. Questo è un po 'più veloce.

Infine, è possibile eseguire più istruzioni SQL in un singolo comando aggiungendo ";" a ogni istruzione, se è necessario eseguire l'intera stringa. È possibile raggruppare un numero di questi comandi insieme e fare una richiesta al server SQL per eseguirli.

Problemi correlati