Самый чистый способ использования beginTransaction с использованием try catch

#c# #transactions

#c# #транзакции

Вопрос:

До сих пор я использую два блока try catch для своих запросов. Первый вызовет ошибку, если соединение не будет установлено. Второй проверяет SqlCommand , выполняется ли он успешно. Как в примере ниже

 try
{
  using(varconnection=newSqlConnection())
  using(varcmd=newSqlCommand())
  {
  
    connection.Open();
    var transaction=connection.BeginTransaction();
    cmd.Connection=connection;
    cmd.Transaction=transaction;

    try
    {
     cmd.CommandText="InsertintoCustomers(Name)values('Dimitri')";
     cmd.ExecuteNonQuery();

     cmd.CommandText="InsertintoCustomers(Name)values('George')";
     cmd.ExecuteNonQuery();

     transaction.Commit();
   }
   catch
   {
     try{transaction.Rollback();}catch{}
   }
  }
}
catch
{

}
 

Я нашел второй пример, который выглядит более понятным для меня.

 SqlTransactiontransaction=null;
using(varconnection=newSqlConnection())
using(varcmd=newSqlCommand())
{
   try
   {
   connection.Open();
   transaction=connection.BeginTransaction();
   cmd.Connection=connection;
   cmd.Transaction=transaction;

   cmd.CommandText="InsertintoCustomers(Name)values('Dimitri')";
   cmd.ExecuteNonQuery();

   cmd.CommandText="InsertintoCustomers(Name)values('George')";
   cmd.ExecuteNonQuery();

   transaction.Commit();
   transaction.Dispose();
   transaction=null;
}
catch
{
   if(transaction!=null)
   {
      try{transaction.Rollback();}catch{}
   }
 }
}
 

Имеют ли они оба одинаковый результат? Какой из двух более предпочтителен?

Комментарии:

1. Если connection.Open(); throws , то это бесполезно transaction.Rollback , и он будет выдавать a NullReferenceException (который будет перехвачен вторым try...catch ).

2. @xanatos в каком случае? … во-первых, open находится вне catch «отката», а во-вторых, есть защита

3. Ни то, ни другое не является предпочтительным, ваш код слишком многословен, даже если вы настаиваете на использовании явных транзакций. TransactionScope Сначала посмотрите вверх. Явное Transaction.Rollback() почти никогда не требуется в любом случае, потому что откат происходит автоматически, если .Commit() он не был вызван к моменту удаления транзакции (что вы должны делать в using блоке).

4. @Selvin В первом, тот, который делает transaction.Rollback() доверие, которое transaction есть != null … Я даже видел (эквивалент второго) transaction?.Rollback() … Но предложения Джеруна намного лучше. using везде, где вы можете, это ключ к исправлению. Сетевое программирование

5. доверие к этой транзакции равно != null , потому что оно не будет null … connection.BeginTransaction возвращает ненулевую транзакцию или выдает … но если throws тогда выполнение завершится внешним пустым catch и никогда не выполнит откат … та же история, когда connection.Open бросит

Ответ №1:

Ни один из этих двух методов не подходит. Они слишком подробны.

Лучший метод — просто поместить Transaction в a using , также мы должны использовать параметр для запроса:

 using(var connection = new SqlConnection(connString))
using(var cmd = new SqlCommand("Insert into Customers (Name) values (@Name));"))
{
    var param = cmd.Parameters.Add("@Name", SqlDbType.VarChar, insert_column_length_here);
    connection.Open();
    using(var transaction = connection.BeginTransaction())
    {
        cmd.Transaction = transaction;
        param.Value = "Dimitri";
        cmd.ExecuteNonQuery();

        param.Value = "George";
        cmd.ExecuteNonQuery();

        transaction.Commit();
    }
}
 

Мы можем видеть, что удаление объекта транзакции автоматически приведет к откату, если он еще не зафиксирован, посмотрев на исходный код. Так using что все очистится.

Если вам нужно перехватить, чтобы отобразить сообщение пользователю, сделайте это вне кода, т. Е. Поместите a try/catch вокруг всего этого. Не выполняйте код очистки самостоятельно

Комментарии:

1. И где я должен разместить try and catch? перед открытием соединения?

2. Ты не try должен или catch что-то в этом роде. using справлюсь со всем этим.

3. Что, если возникнет исключение?

4. using все будет очищено. Если вам нужно перехватить, чтобы отобразить сообщение пользователю, сделайте это вне кода, т. Е. Поместите a try/catch вокруг всего этого. Не выполняйте код очистки самостоятельно

5. Это бессмысленно. Вам нужно поместить try и catch для выполнения отката, если что-то пойдет не так. транзакция. Откат (). За исключением случаев, когда мне не нужен откат в using statement