Не удается получить доступ к объекту SqlTransaction для отката в блоке catch
У меня проблема, и все статьи или примеры, которые я нашел, по-видимому, не заботятся об этом.
Я хочу сделать некоторые действия с базами данных в транзакции. То, что я хочу сделать, очень похоже на большинство примеров:
using (SqlConnection Conn = new SqlConnection(_ConnectionString))
{
try
{
Conn.Open();
SqlTransaction Trans = Conn.BeginTransaction();
using (SqlCommand Com = new SqlCommand(ComText, Conn))
{
/* DB work */
}
}
catch (Exception Ex)
{
Trans.Rollback();
return -1;
}
}
Но проблема в том, что SqlTransaction Trans
объявляется внутри блока try
. Поэтому он недоступен в блоке catch()
. Большинство примеров просто Conn.Open()
и Conn.BeginTransaction()
перед блоком try
, но я думаю, что это немного рискованно, так как оба могут делать несколько исключений.
Я ошибаюсь, или большинство людей просто игнорируют этот риск?
Какое лучшее решение для отката, если происходит исключение?
Ответы
Ответ 1
using (var Conn = new SqlConnection(_ConnectionString))
{
SqlTransaction trans = null;
try
{
Conn.Open();
trans = Conn.BeginTransaction();
using (SqlCommand Com = new SqlCommand(ComText, Conn, trans))
{
/* DB work */
}
trans.Commit();
}
catch (Exception Ex)
{
if (trans != null) trans.Rollback();
return -1;
}
}
или вы можете пойти еще чище и проще и использовать это:
using (var Conn = new SqlConnection(_ConnectionString))
{
try
{
Conn.Open();
using (var ts = new System.Transactions.TransactionScope())
{
using (SqlCommand Com = new SqlCommand(ComText, Conn))
{
/* DB work */
}
ts.Complete();
}
}
catch (Exception Ex)
{
return -1;
}
}
Ответ 2
Мне не нравятся типы ввода и установка переменных в значение null, поэтому:
try
{
using (var conn = new SqlConnection(/* connection string or whatever */))
{
conn.Open();
using (var trans = conn.BeginTransaction())
{
try
{
using (var cmd = conn.CreateCommand())
{
cmd.Transaction = trans;
/* setup command type, text */
/* execute command */
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
/* log exception and the fact that rollback succeeded */
}
}
}
}
catch (Exception ex)
{
/* log or whatever */
}
И если вы хотите переключиться на MySql или другой провайдер, вам нужно будет изменить только одну строку.
Ответ 3
используйте этот
using (SqlConnection Conn = new SqlConnection(_ConnectionString))
{
SqlTransaction Trans = null;
try
{
Conn.Open();
Trans = Conn.BeginTransaction();
using (SqlCommand Com = new SqlCommand(ComText, Conn))
{
/* DB work */
}
}
catch (Exception Ex)
{
if (Trans != null)
Trans.Rollback();
return -1;
}
}
BTW - вы не зафиксировали его в случае успешной обработки
Ответ 4
using (SqlConnection Conn = new SqlConnection(_ConnectionString))
{
try
{
Conn.Open();
SqlTransaction Trans = Conn.BeginTransaction();
try
{
using (SqlCommand Com = new SqlCommand(ComText, Conn))
{
/* DB work */
}
}
catch (Exception TransEx)
{
Trans.Rollback();
return -1;
}
}
catch (Exception Ex)
{
return -1;
}
}
Ответ 5
Образцы Microsoft, поместите начало транс вне try/catch см. эту ссылку msdn. Я предполагаю, что метод BeginTransaction должен либо выдавать исключение, либо начинать транзакцию, но никогда и то и другое (хотя в документации не сказано, что это невозможно).
Однако вам может быть лучше использовать TransactionScope, который управляет большим количеством (не очень) тяжелой работы для вас: эта ссылка
Ответ 6
SqlConnection conn = null;
SqlTransaction trans = null;
try
{
conn = new SqlConnection(_ConnectionString);
conn.Open();
trans = conn.BeginTransaction();
/*
* DB WORK
*/
trans.Commit();
}
catch (Exception ex)
{
if (trans != null)
{
trans.Rollback();
}
return -1;
}
finally
{
if (conn != null)
{
conn.Close();
}
}