C # controla una transacción en múltiples bases de datos

Supongamos que tengo una aplicación de Windows Form que está conectada a n bases de datos, con n conexiones abiertas simultáneamente.

Lo que estoy buscando es hacer una transacción con todas esas bases de datos de una sola vez.

Por ejemplo, si tuviera 2 conexiones de base de datos:

 using (ITransaction tx1 = session1.OpenTransaction()) { using (ITransaction tx2 = session2.OpenTransaction()) { // Do the query thingy here } } 

Escribir todo eso está bien al principio, pero las cosas se vuelven un tanto redundantes cuando quería consultarlas aquí y allá, y sin mencionar la posibilidad de agregar una nueva conexión.

Lo que quería es realizar un ciclo de toda la sesión registrada y finalizarla en un servicio, probablemente algo como esto:

 class TransactionManager { private ISession[] _sessions; public TransactionManager(string[] connectionStrings) { // Initialize the sessions here } public function DoTransaction(string query) { foreach (ISession session in _sessions) { // What to do here? Using? Try-catch? } } } 

Si tuviera que usar usar en el bucle foreach , significaría que si la conexión A era exitosa pero la conexión B no, entonces solo la conexión B se retrotraería.

Parece que puedes estar reinventando TransactionScope . Hacer todo esto bajo una unidad de trabajo es sencillo *:

  using (TransactionScope scope = new TransactionScope()) { ... Do Stuff with Connection 1 using SqlDataReader ... Do Stuff with Connection 2 using Entity Framework ... Do Stuff with Connection 3 on another Oracle Database ... And for good measure do some stuff in MSMQ or other DTC resource scope.Complete(); // If you are happy } 

No es necesario que las Stuff estén en línea en absoluto; pueden estar en una clase diferente o en un ensamblaje diferente. No es necesario registrar explícitamente las conexiones de la base de datos o de la cola con TransactionScope : todo sucede de manera automagically , siempre que los recursos que utiliza puedan enlistarse en una transacción ambiental .

Ahora la letra pequeña:

  • * Cada vez que utilice más de una conexión de base de datos al mismo tiempo, o diferentes cadenas de conexión, o múltiples tecnologías, esto requerirá una confirmación de 2 fases y una escalada a una transacción DTC para garantizar ACID en todos los recursos. DTC en sí tiene muchas más letras pequeñas y plantea muchos más desafíos en una red corporativa , como firewalls , clustering , configuración de seguridad y errores .
  • Sin embargo, con las transacciones Ligeras en MS Sql Server, si puede mantener todas sus conexiones usando la misma base de datos y la misma configuración de cadena de conexión y cierra cada conexión antes de abrir la siguiente, entonces puede evitar el DTC .

  • Mantener una transacción en múltiples recursos de ACID invariablemente mantendrá lockings en estos recursos, hasta que la transacción se confirme o se retrotraiga. Esto a menudo no contribuye a la buena vecindad en una empresa de gran volumen, así que asegúrese de considerar las consecuencias del locking.

  • Si las Stuff se realizan a través de varios hilos, necesitarás cuerda en DependentTransaction

  • Un último punto que vale la pena mencionar es que el nivel de aislamiento predeterminado con TransactionScope es Serializable, que es propenso a interlockings. En la mayoría de los escenarios que no son críticos, probablemente podrá dejar esto en lectura confirmada .

utilice TransactionScope, se encargará de comprometer o anular todas las transacciones incluidas:

 using (var ts = new TransactionScope()) { ... // your old code ts.Complete() }