2008-10-22 22 views
123

¿Cuáles son las mejores prácticas para realizar transacciones en C# .Net 2.0. ¿Cuáles son las clases que deberían usarse? ¿Cuáles son los peligros a tener en cuenta, etc. Todo lo que compromete y revierte cosas? Estoy empezando un proyecto en el que podría necesitar hacer algunas transacciones mientras inserto datos en el DB. Cualquier respuesta o enlace incluso para cosas básicas sobre transacciones son bienvenidas.Transacciones en .net

+0

Aquí hay un buen ejemplo de [Transacciones en .NET] (http://www.codeproject.com/KB/database/transactions.aspx) en el proyecto de código para usar como inicio. –

+2

Útil http://www.codeproject.com/Articles/690136/All-About-TransactionScope – Kiquenet

Respuesta

235

Hay 2 tipos principales de transacciones; transacciones de conexión y transacciones ambientales. Una transacción de conexión (como SqlTransaction) está vinculada directamente a la conexión db (como SqlConnection), lo que significa que debe seguir pasando la conexión, aceptar en algunos casos, pero no permite "crear/usar/liberar" uso, y no permite el trabajo cross-db. Un ejemplo (formateado por espacio):

using (IDbTransaction tran = conn.BeginTransaction()) { 
    try { 
     // your code 
     tran.Commit(); 
    } catch { 
     tran.Rollback(); 
     throw; 
    } 
} 

No demasiado desordenado, pero limitado a nuestra conexión "conn". Si queremos llamar a diferentes métodos, ahora necesitamos pasar "conn".

La alternativa es una transacción ambiental; nuevo en .NET 2.0, el objeto TransactionScope (System.Transactions.dll) permite el uso en un rango de operaciones (los proveedores adecuados se alistarán automáticamente en la transacción ambiental). Esto hace que sea fácil adaptarse al código existente (no transaccional) y hablar con múltiples proveedores (aunque DTC se involucrará si usted habla con más de uno).

Por ejemplo:

using(TransactionScope tran = new TransactionScope()) { 
    CallAMethodThatDoesSomeWork(); 
    CallAMethodThatDoesSomeMoreWork(); 
    tran.Complete(); 
} 

señalar aquí que los dos métodos pueden manejar sus propias conexiones (abierto/uso/cierre/eliminarlo), sin embargo, que en silencio se convertirán en parte de la transacción ambiente sin tener que pasar cualquier cosa en.

Si sus errores de código, se llamará a Dispose() sin completar(), por lo que se retrotraerá. La anidación esperada, etc., es compatible, aunque no puede deshacer una transacción interna y completar la transacción externa: si alguien no está contento, la transacción se cancela.

La otra ventaja de TransactionScope es que no está vinculado solo a las bases de datos; cualquier proveedor de transacciones puede usarlo. WCF, por ejemplo. O incluso hay algunos modelos de objetos compatibles con TransactionScope (es decir, clases .NET con capacidad de reversión, quizás más fácil que un recuerdo, aunque nunca he usado este enfoque).

En general, un objeto muy, muy útil.

Algunas advertencias:

  • En SQL Server 2000, una TransactionScope irá a DTC inmediatamente; esto se soluciona en SQL Server 2005 y posteriores, puede usar el LTM (mucho menos gastos generales) hasta que hable con 2 fuentes, etc., cuando se eleva a DTC.
  • Hay una glitch que significa que puede que tenga que modificar la cadena de conexión
+1

http://www.codeguru.com/columns/vb/article.php/c11067 – Kimoz

+0

¡CSLA .NET 2.0 admite el objeto TransactionScope! –

+0

El problema aquí es cuando tienes una transacción en el primer método y este método (encapsulación) no sabe si se llamará desde una transacción principal o no. –

1

si solo lo necesita para material relacionado con DB, algunos OR Mappers (por ejemplo, NHibernate) admiten transactinos de fábrica por defecto.

0

Depende también de lo que necesita. Para las transacciones SQL básicas, puede intentar realizar transacciones TSQL utilizando BEGIN TRANS y COMMIT TRANS en su código. Esa es la manera más fácil, pero tiene complejidad y debe tener cuidado de comprometerse correctamente (y deshacer).

me gustaría utilizar algo así como

SQLTransaction trans = null; 
using(trans = new SqlTransaction) 
{ 
    ... 
    Do SQL stuff here passing my trans into my various SQL executers 
    ... 
    trans.Commit // May not be quite right 
} 

Cualquier fallo le salen enseguida de la using y la transacción será siempre commit o rollback (dependiendo de lo que diga que haga). El mayor problema al que nos enfrentamos fue asegurarnos de que siempre se haya comprometido. El uso asegura que el alcance de la transacción es limitado.

3

También podría envolver la transacción en su propio procedimiento almacenado y manejarlo de esa manera en lugar de realizar transacciones en C#.

10
protected void Button1_Click(object sender, EventArgs e) 
    { 


     using (SqlConnection connection1 = new SqlConnection("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\Database.mdf;Integrated Security=True;User Instance=True")) 
     { 
      connection1.Open(); 

      // Start a local transaction. 
      SqlTransaction sqlTran = connection1.BeginTransaction(); 

      // Enlist a command in the current transaction. 
      SqlCommand command = connection1.CreateCommand(); 
      command.Transaction = sqlTran; 

      try 
      { 
       // Execute two separate commands. 
       command.CommandText = 
       "insert into [doctor](drname,drspecialization,drday) values ('a','b','c')"; 
       command.ExecuteNonQuery(); 
       command.CommandText = 
       "insert into [doctor](drname,drspecialization,drday) values ('x','y','z')"; 
       command.ExecuteNonQuery(); 

       // Commit the transaction. 
       sqlTran.Commit(); 
       Label3.Text = "Both records were written to database."; 
      } 
      catch (Exception ex) 
      { 
       // Handle the exception if the transaction fails to commit. 
       Label4.Text = ex.Message; 


       try 
       { 
        // Attempt to roll back the transaction. 
        sqlTran.Rollback(); 
       } 
       catch (Exception exRollback) 
       { 
        // Throws an InvalidOperationException if the connection 
        // is closed or the transaction has already been rolled 
        // back on the server. 
        Label5.Text = exRollback.Message; 

       } 
      } 
     } 


    } 
+8

¿Puedes explicar tu código? –