Подтвердить что ты не робот

Не удается получить доступ к объекту 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, но я думаю, что это немного рискованно, так как оба могут делать несколько исключений.

Я ошибаюсь, или большинство людей просто игнорируют этот риск? Какое лучшее решение для отката, если происходит исключение?

4b9b3361

Ответ 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();
   }
}