如何在ASP.Net中的try-catch块之间回滚SQL事务?

时间:2013-04-29 18:42:11

标签: asp.net sql sql-server-2008 transactions

我正在ASP.Net中执行提交例程。问题是,在try-catch块中调试代码时,如果I / user遇到错误,SQL事务永远不会回滚。

如果我在其间中断这个提交例程,SQL Server 2008完全挂起。我甚至无法从SSMS执行选择/插入操作。最后,我必须重新启动SQL Server才能回滚事务。

提交代码:

SqlConnection conn = Db.getConn();
if (conn.State == ConnectionState.Closed) conn.Open();

SqlTransaction trn;
trn = conn.BeginTransaction();

SqlCommand sqlCmd = new SqlCommand("", conn);
sqlCmd.Transaction = trn;

try
{
    string query = GetQuery(); // works fine
    sqlCmd.CommandText = query;

    sqlCmd.ExecuteNonQuery();


    using (SqlBulkCopy bcp = new SqlBulkCopy(conn,SqlBulkCopyOptions.Default, trn))        
        {
            bcp.ColumnMappings.Add("FaYear", "FaYear");
            bcp.ColumnMappings.Add("CostCode", "CostCode");
            bcp.ColumnMappings.Add("TokenNo", "TokenNo");

            bcp.DestinationTableName = "ProcessTokenAddress";
            bcp.WriteToServer(globaltblAddress.DefaultView.ToTable());
        }
    trn.commit();
}
catch (SqlException ex)
{
   trn.Rollback();
}

注意:在这里编写代码时,我意识到我已经捕获 SqlException 而不是异常。这是导致错误的原因吗?唷?

重要事项:我是否需要在Page_UnLoad或其他可处理意外情况的事件处理程序中回滚事务(例如,用户在事务进行时关闭浏览器,用户点击后退按钮等)。

1 个答案:

答案 0 :(得分:1)

首先,在.Net中,您不应该维护一次性重复使用的单一开放连接。这样做的结果实际上正是您所经历的 - 在连接应该关闭的情况下,它不是。

其次,连接实现IDisposable。这意味着应该在using语句或try-catch块中创建和使用它们,其中finally明确关闭连接。如果你有一个自己实现IDisposable的类并且在它自己的生命周期内保持连接,那么你就可以打破这个规则,然后在处理它时关闭它。

您可能会想到通过不打开和关闭连接来提高效率。事实上,你错了,因为.Net为你处理连接池。标准做法是让您传递连接字符串,而不是打开连接对象。您可以将连接字符串包装在将为您返回新连接的类中,但是您不应该保持打开的连接。这样做可能会导致您遇到的错误。

相反,做这些事情:

  1. 使用using语句。这将在创建和使用它们之后正确清理您的连接。

    using (SqlConnection conn = Db.getConn()) {
        conn.Open();
        // your code here
    }
    
  2. 您必须检查连接是否打开这一事实表明问题。不要这样做。相反,请更改Db类中的代码,以便每次都分发新创建的连接。然后你可以确定国家将被关闭,你可以自信地打开它。或者,在Db类中打开连接,但为方法命名以指示连接将打开,例如GetNewOpenConnection。 (尽量避免在方法和类名中使用缩写。)

  3. 我建议您throw出错。虽然记录它而不是抛出它是一种可能的选择,但是在用户坐在计算机上预期结果的任何环境中,简单地吞下错误将不是正确的操作,因为那样你的后来的代码将如何知道发生了错误让用户知道?有必要将异常信息传递给用户。最好不要处理异常,而不是静静地吞下它。

  4. 最后,一个小小的风格是getConn()不遵循C#社区中发现的并且由Microsoft推荐的常规大小写实践。类中的公共方法应以大写字母开头:GetConn()