C#中的SqlConnection - 安全编程实践

7
我在MSDN网站上找到了这段代码,链接在这里:http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.open.aspx
private static void OpenSqlConnection(string connectionString)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        Console.WriteLine("ServerVersion: {0}", connection.ServerVersion);
        Console.WriteLine("State: {0}", connection.State);
    }
}

我的问题是...该网站还指出.Open()可能会抛出InvalidOperationException和SqlException,但是这个示例看起来似乎没有处理它们。
这只是因为他们在代码上简洁明了的原因,还是他们在这里不值得处理?它们可能以某种方式由using结构处理吗?

如果connectionString无效、SqlConnection对象为空或为空,或者无法连接到服务器(或本地数据库),则.Open()将抛出异常。在这种情况下,它们假定连接字符串是有效的,并且使用语句确保连接不为空。 - DangerMonkey
7个回答

9
这只是因为他们在代码中简要处理了吗?或者说它们不值得在这里处理?它们可能会被using构造以某种方式处理吗? using关键字是try/finally的语法糖,即使可能出现异常不会在您引用的代码中处理,SQL连接也将被正确地释放。他们可能没有明确处理可能的异常,因为许多人更喜欢让异常上升到最高层并在那里处理异常。

谢谢大家,这样就清楚多了。我来自C++背景,所以我喜欢仔细检查这些事情,以确保它们不会做得比我想象的更多 :) - John Humphreys

4

MSDN的示例是为了提供易于阅读的示例,而不是教授最佳实践。这也是人们不应该在不理解代码的情况下复制/粘贴代码的原因之一。

根据MSDN所述

using语句以正确的方式调用对象上的Dispose方法,并且(当您像先前显示的那样使用它时)还会导致对象本身在调用Dispose后立即超出范围。

它将通过在try / finally中包装封闭语句来关闭打开的连接(使用finally)。 它不会捕获抛出的异常。 没有catch。


同意。在示例代码中执行最佳实践的问题之一是,新手很难弄清楚正在发生什么。 - NotMe

3

这取决于你是否能够在捕获这些异常时采取任何“操作”。

如果不能 - 通常最好的做法是让异常沿着堆栈向上冒泡,直到它们到达一个有意义的处理点(在Web应用程序的情况下,这可能仅仅是记录500错误)。


2

这些案件正在处理中。

using语句会被转换为适当的处理模式,在异常情况下也可以处理处理,这样即使抛出异常,连接也会被释放。

异常本身会向上冒泡。

有关详细信息,请参见MSDN上的using语句


你可以为我解释得更详细一些,或者给我一个链接让我自己阅读吗? - John Humphreys
1
它们没有被处理 - Kendall Frey
1
@KendallFrey - 不管有没有异常,处理废弃情况的案例都将被处理。重新表述的答案。 - Oded

1
using (SqlConnection connection = new SqlConnection(connectionString))
    {

    }

等同于

try
{

    SqlConnection connection = new SqlConnection(connectionString)
}
finally
{
   connection.Dispose();
}

“using”只是为了确保对象上的dispose()方法被调用(在这种情况下,确保连接返回到连接池中)。 “using”从来没有意味着取代catch。
在我参与的项目中,通常我们有很多try finally。Catch仅在最高级别上用于记录日志。不应使用catch重新抛出错误(而不是记录它)的一个原因是catch非常耗费资源。

0

这个示例虽然从技术上是正确的,但很令人困惑。 在实际应用中,这个“原样”的示例没有价值。
他们甚至没有将SqlConnection返回给调用代码。
所以正如你所说,“他们在代码中简洁明了”。

在实际场景中,你可以有一个像这样的方法

private static SqlConnection OpenSqlConnection(string connectionString) 
{ 
    SqlConnection connection = new SqlConnection(connectionString)
    connection.Open(); 
    return connection;    
} 

然后在你的代码中使用它(虽然并没有太多收益)

using(SqlConnection cnn = OpenSqlConnection(connectionString))
{
    // Do your work here
    ....
}

当然,using语句会隐藏所有捕获异常、关闭/释放资源的工作。因此,从技术上讲,异常得到了处理,但实际上,如果某些操作失败,你并没有得到任何提示。


你说的“没有任何线索”是什么意思?你已经收到了一个异常,这就是一个非常明显的“线索”。 - John Saunders
@JohnSaunders 我在思考这个问题。如果 using 就像一个 try/finally 块,那么如果在 using 块内部出现异常会发生什么?它会向外冒泡并且我们可以注意到它,还是会被 finally 捕获并被闭合括号掩盖? - Steve
刚刚发现了这个,正在阅读以更好地理解。 - Steve
Using 就像 Try/Finally,而不是 Try/Catch。它不会吞掉异常,因为它不会捕获它们。 - John Saunders

0

使用using语句可以确保在调用对象方法时发生异常时也会调用Dispose。try/catch是昂贵的。try/catch可能会影响编译器优化,程序员为什么要使用try/catch而不是像检查null一样简单的操作呢?这只是一个不好的实践。捕获异常总是比进行简单检查慢。我并不是说不要使用它们,但不要将它们用于防御性编程。

此外,查看代码,“open”命令仅在存在有效连接时才会被调用...所以不用担心....

"Using"与将对象放入try块中并在finally块中调用Dispose相同。

如果您仍然需要处理任何特定的异常,请包括try..catch..


“using”并不能防止应用程序崩溃。 - John Saunders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接