Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在ASP.Net中的try-catch块之间回滚SQL事务?_Asp.net_Sql_Sql Server 2008_Transactions - Fatal编程技术网

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

如何在ASP.Net中的try-catch块之间回滚SQL事务?,asp.net,sql,sql-server-2008,transactions,Asp.net,Sql,Sql Server 2008,Transactions,我正在ASP.Net中执行提交例程。问题是,在调试try-catch块中的代码时,如果I/user遇到错误,SQL事务将永远不会回滚 如果中途中断此提交例程,SQL Server 2008将完全挂起。我甚至无法从SSM执行选择/插入操作。最后,我必须重新启动SQL Server才能回滚事务 提交代码: SqlConnection conn = Db.getConn(); if (conn.State == ConnectionState.Closed) conn.Open(); SqlTran

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

如果中途中断此提交例程,SQL Server 2008将完全挂起。我甚至无法从SSM执行选择/插入操作。最后,我必须重新启动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而不是Exception。这就是导致错误的原因吗?呸


重要提示:我是否需要在Page_UnLoad中回滚事务,或者使用其他事件处理程序来处理意外情况,例如,用户在事务进行过程中关闭浏览器,用户单击“后退”按钮等。

首先,在.Net中,您不应该维护一个打开的连接,而需要反复使用它。这样做的结果实际上正是您在应该关闭连接的情况下所经历的,而不是

其次,连接实现IDisposable。这意味着它们应该在using语句中创建和使用,或者在try-catch块中使用finally来显式关闭连接。如果有一个类本身实现IDisposable并在其自身生命周期内保持连接,然后在释放连接时关闭连接,则可以打破此规则

您可能会认为,不总是打开和关闭连接是在提高效率。事实上,您可能错了,因为.Net为您处理连接池。标准做法是传递连接字符串,而不是打开的连接对象。您可以将连接字符串包装到一个类中,该类将为您返回一个新连接,但您不应该维护打开的连接。这样做可能会导致错误,正如您所经历的那样

因此,要做以下事情:

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

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

我建议您抛出错误。虽然记录错误而不抛出错误是一种可能的选择,但在任何情况下,如果用户坐在计算机前等待结果,简单地接受错误将不是正确的操作,因为以后的代码如何知道发生了错误并让用户知道?一些将异常信息传递给用户的方法是必要的。与其默默地接受异常,不如根本不处理异常


最后,有一点需要注意的是,getConn没有遵循C社区中常见的、由微软推荐的正常大写惯例。类中的公共方法应该以大写字母开头:GetConn。

这里有一个最佳实践,尽管它不能解决您的问题:将SqlCommand、SqlConnection和SqlTransaction放入使用块中。这样,不管是否发生异常,它们都会被处理掉。@JohnSaunders-你能为我的案例举个例子吗?我不能正确地完成它。我怀疑它能解决问题,而且时间很短:使用SqlConnection conn=Db.getConn{…}