Транзакции в .net

Каковы наилучшие практики для транзакций на С#.Net 2.0. Какие классы следует использовать? Каковы подводные камни, которые нужно искать и т.д. Все, что совершает и откатывает вещи. Я только начинаю проект, где мне может понадобиться сделать некоторые транзакции, вставляя данные в БД. Любые ответы или ссылки на даже основные вещи о транзакциях приветствуются.

Ответ 1

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

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

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

Альтернативой является внешняя транзакция; new в .NET 2.0, объект TransactionScope (System.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.
  • Существует сбой, что означает, что вам может понадобиться настроить строку подключения

Ответ 2

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;

               }
           }
       }


   }

Ответ 3

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

Ответ 4

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

Ответ 5

Это также зависит от того, что вам нужно. Для основных транзакций 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 и транзакция всегда будет совершать или откатываться (в зависимости от того, что вы скажете ей). Самая большая проблема, с которой мы столкнулись, заключалась в том, чтобы она всегда выполнялась. Использование позволяет ограничить объем транзакции.