Вопрос

Каковы наилучшие методы выполнения транзакций в C # .Net 2.0?Какие классы следует использовать?На какие подводные камни следует обратить внимание и т.д.Вся эта ерунда с фиксацией и откатом.Я только начинаю проект, в котором мне может понадобиться выполнить некоторые транзакции при вставке данных в базу данных.Приветствуются любые ответы или ссылки даже на основные сведения о транзакциях.

Это было полезно?

Решение

Существует 2 основных вида транзакций;транзакции подключения и внешние транзакции.Транзакция подключения (например, SqlTransaction) привязана непосредственно к подключению к БД (например, SqlConnection), что означает, что в некоторых случаях вы должны продолжать передавать соединение по кругу - ОК, но не разрешает использование "создать / использовать / выпустить" и не допускает работу между БД.Пример (отформатированный с учетом пробела):

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

Не слишком грязно, но ограничено нашим соединением "conn".Если мы хотим вызвать разные методы, теперь нам нужно передать "conn" по кругу.

Альтернативой является внешняя транзакция;новое в .NET 2.0, Транзакционный обзор объект (система.Transactions.dll) позволяет использовать в различных операциях (подходящие поставщики будут автоматически подключены к внешней транзакции).Это позволяет легко дорабатывать существующий (не транзакционный) код и общаться с несколькими поставщиками (хотя DTC будет задействован, если вы поговорите более чем с одним).

Например:

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

Обратите внимание здесь, что два метода могут обрабатывать свои собственные соединения (open / use / close / dispose), но они будут незаметно становиться частью внешней транзакции без необходимости нам что-либо передавать.

Если в вашем коде будут ошибки, Dispose() будет вызван без Complete(), поэтому он будет откатан.Ожидаемая вложенность и т.д. Поддерживается, хотя вы не можете откатить внутреннюю транзакцию, пока не завершите внешнюю транзакцию:если кто-то недоволен, транзакция прерывается.

Другим преимуществом TransactionScope является то, что он привязан не только к базам данных;любой поставщик услуг, ориентированный на транзакции, может использовать его.WCF, например.Или есть даже некоторые объектные модели, совместимые с TransactionScope (т. е.Классы .NET с возможностью отката - возможно, проще, чем сувенир, хотя сам я никогда не использовал этот подход).

В общем, очень, очень полезный объект.

Несколько предостережений:

  • На SQL Server 2000 TransactionScope немедленно перейдет в DTC;это исправлено в SQL Server 2005 и выше, он может использовать LTM (гораздо меньше накладных расходов), пока вы не обратитесь к 2 источникам и т.д., когда он повышен до DTC.
  • Существует сбой это означает, что вам, возможно, потребуется изменить строку подключения

Другие советы

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;

               }
           }
       }


   }

Вы также можете заключить транзакцию в собственную хранимую процедуру и обрабатывать ее таким образом, вместо того чтобы выполнять транзакции в самом C #.

если вам это нужно только для вещей, связанных с БД, некоторые OR Mappers (например, NHibernate) поддерживают трансактино из коробки по умолчанию.

Это также зависит от того, что вам нужно. Для базовых транзакций SQL вы можете попробовать выполнить транзакции TSQL, используя в своем коде BEGIN TRANS и COMMIT TRANS. Это самый простой способ, но он имеет сложность, и вы должны быть осторожны, чтобы зафиксировать его правильно (и выполнить откат).

Я бы использовал что-то вроде

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
}

Любой сбой выведет вас прямо из using , и транзакция всегда будет фиксироваться или откатываться (в зависимости от того, что вы скажете). Самая большая проблема, с которой мы столкнулись, заключалась в том, чтобы она всегда была совершенной. Использование гарантирует, что объем транзакции ограничен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top