.net - framework - ¿Es posible usar System.Transactions.TransactionScope con SqlBulkCopy?
transactionscope vb (3)
Pregunta muy simple: ¿es posible usar System.Transactions.TransactionScope
junto con SqlBulkCopy
? La documentación Operaciones de transacciones y copias masivas no menciona nada (al menos a partir de .NET 4.0) y mi prueba indica que no se inscribe automáticamente con TransactionScope
.
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 múltiples hilos y una escritura de múltiples hilos). Obtiene esto cuando usa bcp, inserción masiva, una tarea de flujo de datos ssis con (tablock), una inserción (columnas) seleccione columnas de openrowset (masiva), o una copia de SQL. Esto es útil cuando se trata de minimizar tanto el tiempo de carga como el tamaño del registro de transacciones (solo si ha cumplido con los requisitos mínimos registrados, lo que le ahorrará horas en millones de filas).
Cada vez que cargue datos, el registro de transacciones será el cuello de botella. Si el tiempo es esencial, es importante minimizar cuánto se registra.
Una vez que se cumple el tamaño del lote (el número de filas que especificó para confirmar), la transacción se confirma y comienza de nuevo. Si especifica un tamaño de lote de 0, la transacción cubrirá todo el archivo y la reversión si surge algún problema con los datos.
Para realizar importaciones atómicas de SqlBulkCopy que abarcan todos los lotes (y, opcionalmente, a través de otras declaraciones de la base de datos) necesitamos usar transacciones. Los siguientes pasos describen el proceso de uso de una transacción con SqlBulkCopy:
- Cree un SqlConnection al servidor de base de datos de destino.
- Abra la conexión.
- Crear un objeto SqlTransaction.
- Cree el objeto SqlBulkCopy que pasa en el objeto SqlTransaction al constructor.
- Realice la importación, la llamada a WriteToServer, dentro de un bloque Try ... Catch. Si la operación se completa, cometa la transacción; Si falla, devuélvelo.
SqlBulkCopy
nunca se SqlBulkCopy
en una transacción. SqlCommand
tampoco hace eso. Malentendido común. El alistamiento se realiza en el momento en que se llama a SqlConnection.Open
. Después de eso, todo lo que se ejecuta en esa conexión es parte implícita de la transacción. De hecho ya no está permitido pasar una transacción explícita.
Si desea que SqlBulkCopy
participe en un System.Transactions.Transaction
utilizando TransactionScope
la transacción debe establecerse en el momento en que abra 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 necesitas. Posibles errores:
- La transacción debe abrirse con suficiente antelación.
- No utilice el parámetro
SqlBulkCopy
deSqlBulkCopy
. Pasenull
. - No utilice
SqlBulkCopyOptions.UseInternalTransaction
. - No agregue el manejo de excepciones a menos que realmente desee hacer algo. La reversión es automática si no hay confirmación.
- Utilice la declaración de
using
para el código limpio y la limpieza determinista. No cierre ni deseche ninguno de estos objetos manualmente a menos que tenga que hacerlo. Esto sería redundante.
Puede usar cualquier tamaño de lote que desee y todos los lotes formará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). Trate de no hacer lotes en absoluto primero.