2011-09-06 3 views
25

Domanda molto semplice: è possibile utilizzare System.Transactions.TransactionScope insieme a SqlBulkCopy? La documentazione Transaction and Bulk Copy Operations non menziona nulla (almeno a partire da. NET 4.0) e il mio test indica che non si integra automaticamente con TransactionScope.È possibile utilizzare System.Transactions.TransactionScope con SqlBulkCopy?

+0

ecco alcune risposte su TransactionScope che può essere utile alla vostra situazione http://stackoverflow.com/q/2884863/463478 –

risposta

3

L'unico modo per definire la transazione in un carico di massa (a mia conoscenza) è specificare il lotto di dimensioni.

Il vantaggio del caricamento di massa è che si ottiene un blocco di aggiornamento di massa (lettura multi-thread e una scrittura multi-thread). Si ottiene questo quando si utilizza bcp, bulk-insert, un'attività di flusso di dati ssis con (tablock), un insert (colonne) seleziona colonne da openrowset (bulk) o sqlbulkcopy. Ciò è utile quando si tenta di ridurre al minimo sia il tempo di caricamento sia le dimensioni del log delle transazioni (solo se si sono soddisfatti i requisiti minimi registrati, il che consente di risparmiare ore su milioni di righe).

Ogni volta che si caricano i dati, il log delle transazioni sarà il collo di bottiglia. Se il tempo è essenziale, è importante ridurre al minimo quanto viene registrato.

Una volta che il lotto è soddisfatto (il numero di righe specificato per il commit), la transazione viene confermata e ricomincia. Se si specifica un lotto di 0, la transazione coprirà l'intero file e il rollback in caso di problemi con i dati.

+0

Questo è un peccato. Ho commit di una singola riga e carichi di massa in * più * tabelle seguite da un aggiornamento a riga singola in un'altra tabella che devono tutti avere successo o che nessuno ha successo. Speravo che sarebbe stato facile completare il wrapping dei commit e dei bulkload e l'aggiornamento finale in un 'TransactionScope'. Dovrò solo adottare un approccio diverso. Grazie per la risposta dettagliata, molto apprezzata. – jason

4

Per eseguire importazioni atomiche SqlBulkCopy che si estendono su tutti i batch (e, facoltativamente, su altre istruzioni del database), è necessario utilizzare le transazioni. Le seguenti operazioni delineano il processo di utilizzo di una transazione con SqlBulkCopy:

  1. Creare uno SqlConnection al server di database di destinazione.
  2. Apre la connessione.
  3. Creare un oggetto SqlTransaction.
  4. Creare l'oggetto SqlBulkCopy passando nell'oggetto SqlTransaction nel costruttore.
  5. Eseguire l'importazione - la chiamata a WriteToServer - all'interno di un Prova ... Blocco blocco. Se l'operazione è completata, effettua il commit della transazione; se fallisce, rotola indietro.

Using Transactions with SqlBulkCopy

+0

In cosa sono coinvolti due database? –

+1

Questa risposta non spiega TransactionScope che è stato chiesto. – usr

24

SqlBulkCopy mai arruola in una transazione. SqlCommand inoltre non lo fa. Equivoco comune. L'arruolamento viene eseguito all'ora SqlConnection.Open viene chiamato. Dopodiché, tutto ciò che viene eseguito su quella connessione è implicito nella transazione. Infatti non è più consentito per passare una transazione esplicita.

Se si desidera SqlBulkCopy prendere parte a un System.Transactions.Transaction utilizzando TransactionScope la transazione deve essere impostata nel momento in cui si apre la connessione.

E 'molto facile da fare:

using (var tran = new TransactionScope(...)) 
using (var conn = new SqlConnection(connStr)) 
{ 
    conn.Open(); //This enlists. 

    using (var sqlBulkCopy = new SqlBulkCopy(conn)) { 
    sqlBulkCopy.WriteToServer(...); 
    } 

    tran.Complete(); //Commit. 
} 

Questo codice è tutto ciò che serve. Possibili errori:

  1. La transazione deve essere aperta abbastanza presto.
  2. Non utilizzare il parametro SqlTransaction di SqlBulkCopy. Passa al numero null.
  3. Non utilizzare SqlBulkCopyOptions.UseInternalTransaction.
  4. Non aggiungere la gestione delle eccezioni a meno che non si desideri eseguire effettivamente qualcosa. Il rollback è automatico se non ci sono commit.
  5. Utilizzare l'istruzione using per il codice pulito e la pulizia deterministica. Non chiudere o smaltire manualmente nessuno di questi oggetti, a meno che non sia necessario. Questo sarebbe ridondante.

È possibile utilizzare qualsiasi dimensione di batch che ti piace e tutti i batch faranno parte della transazione. Pertanto, il batching ha un valore limitato (in particolare il log delle transazioni non può essere troncato in anticipo). Per prima cosa non provare a fare il batching.

-1

altro modo può essere utilizzato per ridurre al minimo il tempo di blocco nella vita reale


use SqlBulkCopy and copy data to temporary table use delete output construction to move data into production table