c# - new - unit of work transactionscope
C#controlando una transacción a través de múltiples bases de datos (2)
Supongamos que tengo una aplicación Windows Form que se conecta 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 lo que está bien al principio, pero las cosas se vuelven un tanto redundantes cuando quiero consultar aquí y allá, y sin mencionar la posibilidad de agregar una nueva conexión.
Lo que quería era hacer un bucle de toda la sesión registrada y envolverla 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 el uso en el bucle foreach
, significaría que si la conexión A fue exitosa pero la conexión B no lo fue, entonces solo la conexión B sería retrotraída.
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
}
Stuff
no necesitan estar en línea en absoluto, pueden estar en una clase diferente o en un ensamblaje diferente. No hay necesidad de registrar explícitamente las conexiones de la base de datos o de la cola con el TransactionScope
: todo sucede de forma automagically
, siempre que los recursos que use puedan enlistarse en una transacción ambiental .
Ahora la letra pequeña:
-
*
Cada vez que use más de una conexión de base de datos al mismo tiempo, o cadenas de conexión diferentes o múltiples tecnologías, esto requerirá una confirmación en dos fases y una escalada a una transacciónDTC
para garantizar el ACID en todos los recursos. El propio DTC tiene mucha más letra pequeña y plantea muchos más desafíos en una red corporativa , como firewalls , clustering , configuración de seguridad y bugs . Sin embargo, con las transacciones Lightweight en MS Sql Server, si puede mantener todas sus conexiones utilizando la misma base de datos y la misma configuración de cadena de conexión, y cerrar cada conexión antes de abrir la siguiente, puede evitar el DTC .
Mantener una transacción a través de múltiples recursos ACID invariablemente mantendrá bloqueos en estos recursos, hasta que la transacción se confirme o se revierta. A menudo, esto no favorece la buena vecindad en una empresa de alto volumen, así que asegúrese de considerar las consecuencias del bloqueo.
Si el
Stuff
se realiza a través de varios subprocesos, deberá atar en DependentTransactionUn último punto que vale la pena mencionar es que el nivel de aislamiento predeterminado con
TransactionScope
es Serializable, que es propenso a los interbloqueos. En la mayoría de los escenarios no críticos, es probable que pueda soltar esto en Leer confirmado .
use TransactionScope, se encargará de comprometer o deshacer todas las transacciones incluidas:
using (var ts = new TransactionScope())
{
... // your old code
ts.Complete()
}