是否需要处理SqlTransaction?

13 浏览
0 Comments

是否需要处理SqlTransaction?

在使用SqlTransaction时,我需要在finally块中调用Dispose吗?假设开发人员没有在任何地方使用USING,只是使用了try/catch。\n

SqlTransaction sqlTrans = con.BeginTransaction();
try
{
     //执行操作
     sqlTrans.Commit()
}
catch (Exception ex)
{
     sqlTrans.Rollback();
}
finally
{
     sqlTrans.Dispose();
     con.Dispose();
}

0
0 Comments

从上面的内容中可以得出,问题是关于是否需要显式关闭SqlTransaction。原因是有人认为只需要关闭连接,而不需要显式关闭事务。以下是解决方法:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            // 执行事务操作
            transaction.Commit();
        }
        catch (Exception ex)
        {
            // 处理异常
            transaction.Rollback();
        }
    }
}

根据BCL的代码检查,连接对象会自己处理事务,因此不需要显式关闭事务。然而,更多的代码细节可以提高对此解决方法的信心。

0
0 Comments

Is disposing the SqlTransaction required?这个问题出现的原因是因为在一般情况下,你必须释放每个你构造或获得并拥有的IDisposable对象。但是在某些特殊情况下,有一些例外,并不需要释放,但是SqlTransaction不是其中之一。根据SqlTransaction.Dispose的文档,它释放了DbTransaction使用的非托管资源,并且可选择释放托管资源。由于文档没有说明在提交或回滚时是否释放了这些非托管资源,因此你需要释放这个对象。

解决方法是在使用完SqlTransaction对象后调用Dispose方法来释放资源。示例代码如下:

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    using (SqlTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            // Perform database operations
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine("Error occurred: " + ex.Message);
        }
        finally
        {
            transaction.Dispose();
        }
    }
}

在上述代码中,使用using语句来确保在使用完SqlTransaction对象后自动调用Dispose方法来释放资源。这样可以避免忘记手动释放资源的问题,并且代码更加简洁。

为了释放SqlTransaction对象所使用的资源,需要调用Dispose方法来进行释放。

0
0 Comments

是否需要使用try-finally或using语句来释放SqlTransaction?

它不会有任何问题。这对于实现IDisposable接口的每个类都是真实的,否则它就不会实现这个接口。

但是通常情况下,垃圾回收器处理无引用的对象(这并不意味着GC会调用dispose,这是不正确的),所以只有对于非托管资源才需要它。但是因为我也不想在每个其他变量上调用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也会保持连接的活动状态。它也不保留对事务的引用,因为它只返回事务。因此,即使连接已释放,事务可能也不会被释放。这是释放事务的另一个理由。

您还可以查看BeginSqlTransaction()和Connection.Dispose()代码。SqlTransaction似乎是其清除在Connection.Dispose()中的InternalTransaction的一个包装器。

我不同意评论"This is true for every classs implementing IDisposable"。那HTML控件中的TableCell控件呢?建议不要在它们上面应用'using'。

: 接受意见,那太笼统了。你只需要重写实现或使用using语句,如果你需要释放一些非托管资源,比如数据库连接。控件实现IDisposable是因为控件(例如UserControl)可能包含非托管资源,并且它将在生命周期结束时被释放(递归到所有子控件的页面)。

SqlConnection是否会在SqlConnection被释放时自动释放SqlTransaction?

: 阅读我的回答:"当创建事务时,GC也会保持连接的活动状态。它也不保留对事务的引用,因为它只返回事务。因此,即使连接已释放,事务可能也不会被释放。释放事务的另一个理由。"

我非常确定连接保存对创建的事务对象的引用,并且我在我的项目中使用了该引用。

可以更改“通常情况下,垃圾回收器会处理无引用的对象”这句话的措辞,以避免误导人们认为GC调用Dispose,这是不正确的。

: 已更改 🙂

非常好的回答,谢谢..

0