【问题标题】:asp.net/sql server try catch what is going on?asp.net/sql server try catch 发生了什么?
【发布时间】:2010-11-15 04:17:29
【问题描述】:

我在我的代码中发现了一个错误,我对它最初是如何发生的感到困惑。

我的问题是,我在数据库 ID 字段中发现了一个跳过(它是一个递增的标识字段),表明没有插入一些记录 - 这意味着我的 SQL 存储过程(可能)抛出了一个错误。从那里往后想,这意味着我的业务对象应该已经捕捉到该错误并抛出它,立即退出并返回到页面的代码隐藏(而是继续到第二个存储过程)。我不明白为什么或如何做到这一点。跳过我的 try 捕获的代码执行是怎么回事?

后面的页面代码:

 protected void submitbutton_click(object sender, EventArgs e){
      try{
        mybusinessobject.savetodatabase()
      } catch( Exception ex) {
        Response.Redirect("Error.aspx");
      }
 }

业务对象代码:

 public static void savetodatabase(){
        int ID1=-1;
        int ID2=-1;
        //store the billing contact
        SqlCommand cmd1 = new SqlCommand("SaveInfo1", con);
        cmd1.CommandType = CommandType.StoredProcedure;
        //...
        cmd1.Parameters.Add("@Ret", SqlDbType.Int);
        cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue;

        try
        {
            con.Open();
            cmd1 .ExecuteNonQuery();
            ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value);
        }
        catch (Exception ex) { throw ex; }
        finally { con.Close(); }

        if (ID1  > 0)
        {
            SqlCommand cmd = new SqlCommand("SaveInfo2", con);
            cmd.CommandType = CommandType.StoredProcedure;
            //...
            try
            {
                con.Open();
                cmd.ExecuteNonQuery();
                ID2= Convert.ToInt32(cmd.Parameters["@Ret"].Value);
            }
            catch (Exception ex) { throw ex; }
            finally { con.Close(); }
        }
 }

SQL 代码:

PROCEDURE [dbo].[SaveInfo1]
( 
-- ... parameters ...
)
AS
    INSERT INTO Table1 ( ... ) Values ( ... )
RETURN SCOPE_IDENTITY

PROCEDURE [dbo].[SaveInfo2]
( 
-- ... parameters ...
)
AS
    DECLARE @SpecialID INT
    INSERT INTO Table2 ( ... ) Values ( ... )
    SET @SpecialID = SCOPE_IDENTITY()
    INSERT INTO Table3 ( [ID],  ... ) Values ( @SpecialID, ... )
RETURN SCOPE_IDENTITY()

【问题讨论】:

  • 我不使用 asp.net,所以我可能会错过这里的船。它不会引起您所询问的问题,但是否存在围绕两个存储过程调用的事务?
  • 不,这是问题的一部分。但这仍然不能解释为什么它跳过了我的尝试捕获。
  • 看我的回答。我确定我是对的。在找到解决方案之前,我一直在绞尽脑汁试图解决同一个问题几周

标签: asp.net sql exception exception-handling


【解决方案1】:

您的异常处理很糟糕。 永远不要这样做:

catch (Exception ex) { throw ex; }

所要做的就是搞砸异常中的堆栈跟踪。它使它看起来像是源自throw 的异常。

永远不要这样做:

  try{
    mybusinessobject.savetodatabase()
  } catch( Exception ex) {
    Response.Redirect("Error.aspx");
  }

你不知道发生了什么异常。您不知道重定向是否安全,最重要的是,您会丢失所有关于异常是什么的信息!

您还应该养成实现using 块的习惯:

public static void savetodatabase()
{
    using (SqlConnection con = new SqlConnection("Connectionstring"))
    {
        int ID1;
        //store the billing contact
        using (SqlCommand cmd1 = new SqlCommand("SaveInfo1", con))
        {
            cmd1.CommandType = CommandType.StoredProcedure;
            //...
            cmd1.Parameters.Add("@Ret", SqlDbType.Int);
            cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue;

            con.Open();
            cmd1.ExecuteNonQuery();
            ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value);
        }

        if (ID1 <= 0)
        {
            return;
        }

        int ID2 = -1;
        using (SqlCommand cmd = new SqlCommand("SaveInfo2", con))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            //...
            con.Open();
            cmd.ExecuteNonQuery();
            ID2 = Convert.ToInt32(cmd.Parameters["@Ret"].Value);
        }
    }
}

using 块将确保资源将调用其Dispose 方法,无论是否引发异常。

【讨论】:

    【解决方案2】:

    更有可能的情况不是有人刚刚从表中删除了一些记录吗?

    【讨论】:

    • 在您的第一个过程中您返回 RETURN SCOPE_IDENTITY 而不是 RETURN SCOPE_IDENTITY() 是否重要?
    【解决方案3】:

    如果记录被删除,它们的唯一标识符将不会被回收,即使稍后插入新记录也是如此。如果您愿意,可以在 SQL 中使用 RESEED 将标识种子重置为 0,但我建议您不要这样做,除非您擦除表。否则,您最终可能会违反主键。

    另外,请确保您的列的标识种子一次设置为递增 1。

    【讨论】:

      【解决方案4】:

      您的代码无关紧要,只需转到 Web.config 并使用适当的节点即可:

      <customErrors mode="On|Off" />
      

      附: 使用using 子句自动关闭连接,而不是在finally 子句中手动关闭

      【讨论】:

      • 这对于异常是否被catch 块捕获绝对没有影响(它们总是被捕获)。
      • 不,他们没有!对 customErrors 的每个可能值进行测试,您将看到。我在 VS2008TS/SQL2008/Win7RC 上遇到了同样的问题。不然就瞎了眼!
      【解决方案5】:

      你可以测试一下。只需更改程序:

      PROCEDURE [dbo].[SaveInfo1]
      ( 
      -- ... parameters ...
      )
      AS
          INSERT INTO Table1 ( ... ) Values ( ..., some_out_of_range_value_here, ....)
      RETURN SCOPE_IDENTITY()
      

      有一些硬编码超出范围的值(因此插入失败),然后运行您的应用程序...

      【讨论】:

        猜你喜欢
        • 2016-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多