SqlTransaction должен вызывать Dispose? - PullRequest
6 голосов
/ 02 марта 2012

Нужно ли вызывать dispose в блоке finally для SqlTransaction?Притворись, что разработчик нигде не использовал USING, а просто попробуй / поймай.

SqlTransaction sqlTrans = con.BeginTransaction();

try
{
     //Do Work
sqlTrans.Commit()
}
catch (Exception ex)
        {

           sqlTrans.Rollback();
        }

 finally
        {
            sqlTrans.Dispose();
            con.Dispose();
        }

Ответы [ 3 ]

11 голосов
/ 02 марта 2012

Нужно ли использовать try-finally или using заявление для распоряжения SqlTransaction?

Это не помешает иметь его.Это верно для каждого класса, реализующего IDisposable , в противном случае он не будет реализовывать этот интерфейс.

Но обычно сборщик мусора будет иметь дело с ним, если на объект больше не будут ссылаться.Поскольку я также не хочу вызывать dispose для каждой второй переменной или везде использовать using-оператор , всегда стоит взглянуть на фактическую реализацию метода класса Dispose.

SqlTransaction.Dispose:

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        SNIHandle target = null;
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection);
            if (!this.IsZombied && !this.IsYukonPartialZombie)
            {
                this._internalTransaction.Dispose();
            }
        }
        catch (OutOfMemoryException e)
        {
            this._connection.Abort(e);
            throw;
        }
        catch (StackOverflowException e2)
        {
            this._connection.Abort(e2);
            throw;
        }
        catch (ThreadAbortException e3)
        {
            this._connection.Abort(e3);
            SqlInternalConnection.BestEffortCleanup(target);
            throw;
        }
    }
    base.Dispose(disposing);
}

Не понимая всего (или чего-либо), что здесь происходит, я могу сказать, что это больше, чем просто base.Dispose(disposing).Поэтому может быть хорошей идеей обеспечить удаление SqlTransaction.

Но поскольку SqlConnection.BeginTransaction создает транзакцию, также может быть хорошей идеей отразить это также:

public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName)
{
    SqlStatistics statistics = null;
    string a = ADP.IsEmpty(transactionName) ? "None" : transactionName;
    IntPtr intPtr;
    Bid.ScopeEnter(out intPtr, "<sc.SqlConnection.BeginTransaction|API> %d#, iso=%d{ds.IsolationLevel}, transactionName='%ls'\n", this.ObjectID, (int)iso, a);
    SqlTransaction result;
    try
    {
        statistics = SqlStatistics.StartTimer(this.Statistics);
        SqlTransaction sqlTransaction = this.GetOpenConnection().BeginSqlTransaction(iso, transactionName);
        GC.KeepAlive(this);
        result = sqlTransaction;
    }
    finally
    {
        Bid.ScopeLeave(ref intPtr);
        SqlStatistics.StopTimer(statistics);
    }
    return result;
}

Как видите. GC также будет поддерживать соединение в действии при создании транзакции.Он также не содержит ссылку на транзакцию, поскольку он только возвращает ее.Следовательно, он не может быть утилизирован, даже если соединение уже удалено.Еще один аргумент для удаления транзакции.

Вы также можете взглянуть на TransactionScope класс , который более надежен, чем BeginTransaction.Посмотрите этот вопрос для получения дополнительной информации.

8 голосов
/ 02 марта 2012

В общем случае каждый объект IDisposable, который вы строите или приобретаете, а также владеете, вы должны утилизировать.

В конкретном случае есть некоторые исключения, но SqlTransaction - это не одноиз них.

Согласно документации SqlTransaction.Dispose:

Освобождает неуправляемые ресурсы , используемые DbTransaction и при необходимостиосвобождает управляемые ресурсы.

(мой акцент)

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

0 голосов
/ 02 марта 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...