如何在ASP.Net中的try-catch块之间回滚SQL事务?
我正在ASP.Net中执行提交例程。问题是,在调试try-catch块中的代码时,如果I/user遇到错误,SQL事务将永远不会回滚 如果中途中断此提交例程,SQL Server 2008将完全挂起。我甚至无法从SSM执行选择/插入操作。最后,我必须重新启动SQL Server才能回滚事务 提交代码:如何在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
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{…}