web-dev-qa-db-fra.com

Transactions en .net

Quelles sont les meilleures pratiques pour effectuer des transactions en C # .Net 2.0. Quelles sont les classes qui devraient être utilisées? Quels sont les pièges à surveiller, etc. Tous ces trucs de validation et d'annulation. Je commence juste un projet où je pourrais avoir besoin de faire des transactions tout en insérant des données dans la base de données. Toutes les réponses ou liens pour des informations de base sur les transactions sont les bienvenus.

140

Il existe 2 principaux types de transactions; transactions de connexion et transactions ambiantes. Une transaction de connexion (telle que SqlTransaction) est directement liée à la connexion à la base de données (telle que SqlConnection), ce qui signifie que vous devez continuer à passer la connexion - OK dans certains cas, mais n'autorisez pas "créer/utiliser/libérer" utilisation, et ne permet pas le travail cross-db. Un exemple (formaté pour l'espace):

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

Pas trop brouillon, mais limité à notre connexion "conn". Si nous voulons faire appel à différentes méthodes, nous devons maintenant passer "conn".

L'alternative est une transaction ambiante; Nouveau dans .NET 2.0, l’objet TransactionScope (System.Transactions.dll) permet une utilisation sur une plage d’opérations (les fournisseurs appropriés s’enregistrent automatiquement dans la transaction ambiante). Cela facilite la réintégration dans le code existant (non transactionnel) et la possibilité de parler à plusieurs fournisseurs (bien que le DTC intervienne si vous parlez à plus d'un).

Par exemple:

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

Notez ici que les deux méthodes peuvent gérer leurs propres connexions (open/use/close/dispose), mais elles feront silencieusement partie de la transaction ambient sans que nous ayons à passer quoi que ce soit.

Si votre code est erroné, Dispose () sera appelé sans Complete () et sera donc annulé. L'emboîtement prévu, etc. est pris en charge, même si vous ne pouvez pas annuler une transaction interne tout en complétant la transaction externe: si quelqu'un n'est pas satisfait, la transaction est annulée.

L’autre avantage de TransactionScope est qu’il n’est pas uniquement lié aux bases de données; tout fournisseur sensible aux transactions peut l'utiliser. WCF, par exemple. Ou encore, il existe même des modèles d’objets compatibles avec TransactionScope (par exemple, des classes .NET avec une fonction d’annulation - peut-être plus facile qu’un mémento, même si je n’ai jamais utilisé cette approche moi-même).

Dans l'ensemble, un objet très, très utile.

Quelques mises en garde:

  • Sur SQL Server 2000, un TransactionScope ira immédiatement vers DTC; cela est corrigé dans SQL Server 2005 et versions ultérieures, il peut utiliser le LTM (beaucoup moins de temps système) jusqu’à ce que vous parliez à 2 sources, etc., lorsqu’il passe au DTC.
  • Il y a un pépin cela signifie que vous devrez peut-être modifier votre chaîne de connexion
261
Marc Gravell
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;

               }
           }
       }


   }
11
Ali Gholizadeh

Vous pouvez également intégrer la transaction dans sa propre procédure stockée et la gérer de cette façon au lieu d'effectuer des transactions en C # lui-même.

3
Charles Graham

si vous en avez juste besoin pour des choses liées à la base de données, certains OR Les mappeurs (par exemple, NHibernate) prennent en charge les transactions par défaut.

1

Cela dépend aussi de ce dont vous avez besoin. Pour les transactions SQL de base, vous pouvez essayer de faire des transactions TSQL en utilisant BEGIN TRANS et COMMIT TRANS dans votre code. C’est le moyen le plus simple, mais il est complexe et vous devez faire attention à vous engager correctement (et à revenir en arrière).

Je voudrais utiliser quelque chose comme

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
}

Tout échec vous échappera du using et la transaction sera toujours validée ou annulée (selon ce que vous lui dites de faire). Le plus gros problème auquel nous avons été confrontés a été de nous assurer qu’il était toujours engagé. L'utilisation garantit que la portée de la transaction est limitée.

0
Brody