2011-09-06 27 views
25

Pregunta muy simple: ¿es posible usar System.Transactions.TransactionScope junto con SqlBulkCopy? La documentación Transaction and Bulk Copy Operations no menciona nada (al menos a partir de .NET 4.0) y mis pruebas indican que no se alista automáticamente con TransactionScope.¿Es posible usar System.Transactions.TransactionScope con SqlBulkCopy?

+0

Aquí es algunas respuestas acerca TransactionScope que puede ser útil para su situación http://stackoverflow.com/q/2884863/463478 –

Respuesta

3

La única forma de definir la transacción en una carga masiva (que yo sepa) es especificar el tamaño del lote.

La ventaja de la carga masiva es que obtiene un bloqueo de actualización masiva (lectura de subprocesos múltiples y escritura de subprocesos múltiples). Usted obtiene esto cuando usa bcp, inserción masiva, una tarea de flujo de datos ssis con (tablock), un inserto (columnas) selecciona columnas de openrowset (bulk), o un sqlbulkcopy. Esto es útil cuando se trata de minimizar el tiempo de carga y el tamaño del registro de transacciones (solo si ha cumplido con los requisitos mínimamente registrados, lo que le ahorrará horas en millones de filas).

Cada vez que carga datos, el registro de transacciones será el cuello de botella. Si el tiempo es esencial, es importante minimizar la cantidad que se registra.

Una vez que se cumple el tamaño del lote (el número de filas que usted especificó para comprometer) la transacción se compromete y comienza de nuevo. Si especifica un tamaño de lote de 0, la transacción cubrirá el archivo completo y la reversión si surge algún problema de datos.

+0

Eso es desafortunado. Tengo confirmaciones de una sola fila y cargas masivas en * tablas * múltiples seguidas de una actualización de una fila en otra tabla que tienen que tener éxito o ninguna tiene éxito. Esperaba que fuera fácil de lograr envolver los commits y las cargas masivas y la actualización final en un 'TransactionScope'. Tendré que tomar un enfoque diferente. Gracias por la respuesta detallada, muy apreciada. – jason

4

Para realizar importaciones atómicas de SqlBulkCopy que abarquen todos los lotes (y, opcionalmente, a través de otras declaraciones de base de datos), necesitamos usar transacciones. Los pasos siguientes describen el proceso de uso de una transacción con SqlBulkCopy:

  1. Cree una conexión Sql al servidor de la base de datos de destino.
  2. Abra la conexión.
  3. Crea un objeto SqlTransaction.
  4. Crea el objeto SqlBulkCopy que pasa en el objeto SqlTransaction en el constructor.
  5. Realice la importación - la llamada a WriteToServer - dentro de un Try ... Catch block. Si la operación se completa, confirme la transacción; si falla, arrástralo hacia atrás.

Using Transactions with SqlBulkCopy

+0

¿Qué tenemos dos bases de datos involucradas? –

+1

Esta respuesta no explica TransactionScope que se le preguntó. – usr

24

SqlBulkCopy nunca se alista en una transacción. SqlCommand tampoco hace eso. Malentendido común. El alistamiento se realiza en el momento en que se llama al SqlConnection.Open. Después de eso, todo lo que se ejecuta en esa conexión es parte de la transacción implícitamente. De hecho, ya no es permitido para pasar una transacción explícita.

Si quiere SqlBulkCopy para tomar parte en un System.Transactions.Transaction utilizando TransactionScope, la transacción debe establecerse en el momento de abrir la conexión.

Es muy fácil de hacer:

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. 
} 

Este código es todo lo que necesita. Posibles errores:

  1. La transacción se debe abrir lo suficientemente temprano.
  2. No utilice el parámetro SqlTransaction de SqlBulkCopy. Pase null.
  3. No utilice SqlBulkCopyOptions.UseInternalTransaction.
  4. No agregue el manejo de excepciones a menos que desee realmente hacer algo. La reversión es automática si no hay commit.
  5. Utilice la declaración using para el código limpio y la limpieza determinista. No cierre ni deseche manualmente ninguno de estos objetos a menos que sea necesario. Esto sería redundante.

Puede usar cualquier tamaño de lote que desee y todos los lotes serán parte de la transacción. Por lo tanto, el procesamiento por lotes tiene un valor limitado (en particular, el registro de transacciones no se puede truncar antes). Intenta no hacer un lote al principio.

-1

forma adicional se puede utilizar para minimizar el tiempo de bloqueo en la vida real


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

Cuestiones relacionadas