Pregunta

¿Cuáles son las mejores prácticas para realizar transacciones en C # .Net 2.0? ¿Cuáles son las clases que deben usarse? ¿Cuáles son los peligros a los que hay que estar atentos? Todo lo que se compromete y se deshace. Estoy empezando un proyecto en el que podría necesitar hacer algunas transacciones al insertar datos en la base de datos. Cualquier respuesta o enlace para incluso cosas básicas sobre transacciones son bienvenidos.

¿Fue útil?

Solución

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 tiene que seguir transmitiendo la conexión, en algunos casos, está bien, pero no permite " crear / usar / liberar " ; uso, y no permite el trabajo de db cross. Un ejemplo (formateado para el espacio):

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

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

La alternativa es una transacción ambiental; nuevo en .NET 2.0, el objeto TransactionScope (Sistema .Transactions.dll) permite su uso en un rango de operaciones (los proveedores adecuados se enlistarán automáticamente en la transacción ambiental). Esto facilita la adaptación en el código existente (no transaccional) y hablar con múltiples proveedores (aunque DTC se involucrará si habla con más de uno).

Por ejemplo:

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

Tenga en cuenta que los dos métodos pueden manejar sus propias conexiones (abrir / usar / cerrar / disponer), sin embargo, se convertirán en parte de la transacción ambiental sin que tengamos que pasar nada.

Si se produce un error en el código, se llamará a Dispose () sin Complete (), por lo que se revertirá. Se admite el anidamiento esperado, etc., aunque no puede revertir una transacción interna y completar la transacción externa: si alguien está descontento, la transacción se cancela.

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

En definitiva, un objeto muy, muy útil.

Algunas advertencias:

  • En SQL Server 2000, un TransactionScope irá a DTC inmediatamente; esto se solucionó en SQL Server 2005 y superior, puede usar el LTM (mucho menos gastos generales) hasta que hable con 2 fuentes, etc., cuando se eleva a DTC.
  • Hay un error técnico que significa que es posible que tengas que modificar su cadena de conexión

Otros consejos

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;

               }
           }
       }


   }

También puede ajustar la transacción en su propio procedimiento almacenado y manejarlo de esa manera en lugar de realizar transacciones en C #.

si solo lo necesita para cosas relacionadas con db, algunos OR Mappers (por ejemplo, NHibernate) admiten transactinos fuera de la caja por defecto.

También depende de lo que necesites. Para transacciones SQL básicas, puede intentar hacer transacciones TSQL usando BEGIN TRANS y COMMIT TRANS en su código. Esa es la forma más fácil, pero tiene complejidad y hay que tener cuidado de confirmar (y revertir) correctamente.

Yo usaría algo 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 falla lo sacará del usando y la transacción siempre se confirmará o revertirá (dependiendo de lo que le diga que haga). El mayor problema que enfrentamos fue asegurarse de que siempre se cometiera. El uso garantiza que el alcance de la transacción sea limitado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top