使用 SQLDataReader 对象时关闭 SQLConnection 对象的重要性

发布于 2024-07-09 10:56:43 字数 1268 浏览 6 评论 0原文

我目前的合同工作是在一家大型电子商务公司。 他们的代码库的起源可以追溯到.Net 1.0,这让我大吃一惊,其中包含许多问题,这些问题使我的嗅觉水平超出了我上次的垃圾水平。

尽管如此,并试图分散我的注意力,我还是愉快地尝试添加功能来解决其他问题或扩展更多垃圾。 当我触摸 DAL/BLL 时,修复上述问题所需的时间就会完成。 然而,我希望得到专家们的信任投票,以确保不会浪费客户的时间,或者更糟糕的是,我的可信度会因接触“有效的东西”而被否决。 当然,单元测试可以解决或至少减轻这种担忧。 也许这也应该添加到 wtf.com 中?

Public Function GetSizeInfoBySite(ByVal siteID As String) As IList
    Dim strSQL As String = "YES INLINE SQL!! :)"
    Dim ci As CrapInfo
    Dim alAnArrayList As ArrayList

    Dim cn As New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
    Dim cmd As New SqlCommand(strSQL, cn)
    cmd.Parameters.Add(New SqlParameter("@MySiteID", SqlDbType.NVarChar, 2)).Value = siteID
    cn.Open()
    Dim rs As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    While rs.Read()
        ci = New CategoryInfo(rs("someID"), rs("someName"))
        If IsNothing(alAnArrayList) Then
            alAnArrayList = New ArrayList
        End If
        alAnArrayList.Add(ci)
    End While
    rs.Close()
    Return CType(alAnArrayList, IList)
End Function

除了让我感到不安的内联 SQL 之外,还有人看到这个问题吗? 至少,您通常不会将上述内容包装在我们大多数人都知道自 .Net v1.0 以来就存在的 try/catch/finally 中吗? 更好的是,用Using语句修复不是更明智吗? SQLDataReader close 是否真的封装了连接自动关闭?

My present contract engagement is at a large E-Commerce company. Their code base which has origins going back to .Net 1.0 has caught me by surprise to contain many issues that raise the level of smell beyond the last crap I took.

That notwithstanding and trying to diffuse my level of distraction from it, I go along merrily trying to add in features to either fix other problems or extend more crap. Where I touch the DAL/BLL the time it will take to fix the aforementioned will be done. However I wanted to get a vote of confidence from the experts to get some assurance of not wasting the clients time or worse having my credibility voted down by touching "stuff that works". Of course unit testing would solve or at least soften this worry. Perhaps this should also be added to the wtf.com?

Public Function GetSizeInfoBySite(ByVal siteID As String) As IList
    Dim strSQL As String = "YES INLINE SQL!! :)"
    Dim ci As CrapInfo
    Dim alAnArrayList As ArrayList

    Dim cn As New SqlConnection(ConfigurationSettings.AppSettings("ConnectionString"))
    Dim cmd As New SqlCommand(strSQL, cn)
    cmd.Parameters.Add(New SqlParameter("@MySiteID", SqlDbType.NVarChar, 2)).Value = siteID
    cn.Open()
    Dim rs As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    While rs.Read()
        ci = New CategoryInfo(rs("someID"), rs("someName"))
        If IsNothing(alAnArrayList) Then
            alAnArrayList = New ArrayList
        End If
        alAnArrayList.Add(ci)
    End While
    rs.Close()
    Return CType(alAnArrayList, IList)
End Function

Does anyone see problems with this aside from the inline SQL which makes my gut churn? At the least wouldn't you ordinarily wrap the above in a try/catch/finally which most of us knows has been around since .Net v1.0? Even better would'nt it be wise to fix with Using statements? Does the SQLDataReader close really encapsulate the connection close automagically?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

残月升风 2024-07-16 10:56:43

如果用户输入被正确参数化,那么内联 sql 没有任何问题,看起来确实如此。

除此之外,是的,您确实需要关闭连接。 在繁忙的网站上,您可能会达到极限,这会导致各种奇怪的情况。

我还注意到它仍然使用数组列表。 由于它们已经从 .Net 1.0 发展而来,因此是时候将它们更新为通用 List(并避免调用 CType - 您应该能够使用 DirectCast() 来代替)。

Nothing wrong with inline sql if the user input is properly parameterized, and this looks like it is.

Other than that, yes you do need to close the connections. On a busy web site you could hit your limit and that would cause all kinds of weirdness.

I also noticed it's still using an arraylist. Since they've moved on from .Net 1.0 it's time to update those to generic List<T>'s (and avoid the call to CType- you should be able to DirectCast() that instead).

辞别 2024-07-16 10:56:43

一定要在 Connection 和 Reader 对象周围使用一些 using 语句。 如果出现异常,它们将不会被关闭,直到垃圾收集器处理它们为止。

当有 using 语句时,我倾向于不调用 .Close() 。 即使 SqlDataReader 在处置时关闭连接(检查 doco),在 Connection 周围放置 using 也不会造成伤害并坚持模式。

如果你这样做,只有当你需要在那里进行异常处理时才需要 try/finally 。 我倾向于将异常处理留在较高级别(包装每个 UI 入口点、库入口点、异常中的额外信息),因为堆栈跟踪通常足以调试错误。

这并不重要,但如果要重构,请将集合初始化移到循环之外。 再想一想,如果没有记录,代码将返回 null。

至少使用了SqlParameters! 如果发现任何将用户输入与 SQL 连接起来的东西(SQL 注入攻击),无论它“清理”得多么好,都将其删除。

Definitely get some using statements around the Connection and Reader objects. If there is an exception, they won't be closed until the Garbage Collector gets around to them.

I tend not to call .Close() when there are using statements. Even if the SqlDataReader closes the connection on dispose (check the doco), putting a using around the Connection can't hurt and sticks to the pattern .

If you do that the try/finally is only needed if you need to do exception handling right there. I tend to leave exception handling at the higher levels (wrap each UI entry point, Library entry points, extra info in exception) as the stacktrace is usually enough to debug the errors.

Not that it matters much, but if you are re-factoring, move the collection initialization outside the loop. On second thoughts the code returns null if there are no records.

At least SqlParameters are used! Get rid of anything that concatenates user input with SQL if you find it (SQL Injection attack) no matter how well "Cleaned" it is.

终遇你 2024-07-16 10:56:43

当阅读器关闭时,连接将关闭,因为它使用 CloseConnection 命令行为。

Dim rs As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)

根据 MSDN (http://msdn.microsoft.com /en-us/library/aa326246(VS.71).aspx)

如果创建 SqlDataReader 时将 CommandBehavior 设置为 CloseConnection,则关闭 SqlDataReader 会自动关闭连接。

The connection will be closed when the reader is closed because it's using the CloseConnection command behavior.

Dim rs As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)

According to MSDN (http://msdn.microsoft.com/en-us/library/aa326246(VS.71).aspx)

If the SqlDataReader is created with CommandBehavior set to CloseConnection, closing the SqlDataReader closes the connection automatically.

国粹 2024-07-16 10:56:43

为了回应乔尔和罗伯特提出的一些重要观点,我重构了如下方法,该方法运行完美。

Public Function GetSomeInfoByBusObject(ByVal SomeID As String) As IList
Dim strSQL As String = "InLine SQL"
Dim ci As BusObject
Dim list As New GenList(Of BusObject)
Dim cn As New SqlConnection(
    ConfigurationSettings.AppSettings("ConnectionString"))
Using cn
    Dim cmd As New SqlCommand(strSQL, cn)
    Using cmd
        cmd.Parameters.Add(New SqlParameter
            ("@SomeID", SqlDbType.NVarChar, 2)).Value = strSiteID
        cn.Open()
            Dim result As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
                While result.Read()
                    ci = New BusObject(rs("id), result("description"))
                    list.Add(DirectCast(ci, BusObject))
                End While
            result.Close()
        End Using
    Return list
End Using

End Function

创建了一个漂亮的小帮助器类来包装通用细节

Public Class GenList(Of T)
    Inherits CollectionBase
    Public Function Add(ByVal value As T) As Integer
        Return List.Add(value)
    End Function
    Public Sub Remove(ByVal value As T)
        List.Remove(value)
    End Sub
    Public ReadOnly Property Item(ByVal index As Integer) As T
        Get
            Return CType(List.Item(index), T)
        End Get
    End Property
End Class

In reply to some of the great points indicated by Joel and Robert I refactored the method as follows which ran flawless.

Public Function GetSomeInfoByBusObject(ByVal SomeID As String) As IList
Dim strSQL As String = "InLine SQL"
Dim ci As BusObject
Dim list As New GenList(Of BusObject)
Dim cn As New SqlConnection(
    ConfigurationSettings.AppSettings("ConnectionString"))
Using cn
    Dim cmd As New SqlCommand(strSQL, cn)
    Using cmd
        cmd.Parameters.Add(New SqlParameter
            ("@SomeID", SqlDbType.NVarChar, 2)).Value = strSiteID
        cn.Open()
            Dim result As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
                While result.Read()
                    ci = New BusObject(rs("id), result("description"))
                    list.Add(DirectCast(ci, BusObject))
                End While
            result.Close()
        End Using
    Return list
End Using

End Function

Created a nice little helper class to wrap the generic details up

Public Class GenList(Of T)
    Inherits CollectionBase
    Public Function Add(ByVal value As T) As Integer
        Return List.Add(value)
    End Function
    Public Sub Remove(ByVal value As T)
        List.Remove(value)
    End Sub
    Public ReadOnly Property Item(ByVal index As Integer) As T
        Get
            Return CType(List.Item(index), T)
        End Get
    End Property
End Class
云柯 2024-07-16 10:56:43

如果您使用 C#,我会将数据读取器创建包装在 using 语句中,但我认为 VB 没有这些?

If you were using c# I would wrap the datareader creation in a using statement but I don't think vb has those?

左耳近心 2024-07-16 10:56:43
Public Function GetSizeInfoBySite(ByVal siteID As String) As IList(Of CategoryInfo)
        Dim strSQL As String = "YES INLINE SQL!! :)"

        'reference the 2.0 System.Configuration, and add a connection string section to web.config
        '  <connectionStrings>
        '   <add name="somename" connectionString="someconnectionstring" />
        '  </connectionStrings >

        Using cn As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("somename").ConnectionString

            Using cmd As New SqlCommand(strSQL, cn)

                cmd.Parameters.Add(New SqlParameter("@MySiteID", SqlDbType.NVarChar, 2)).Value = siteID
                cn.Open()

                Using reader As IDataReader = cmd.ExecuteReader()

                    Dim records As IList(Of CategoryInfo) = New List(Of CategoryInfo)

                    'get ordinal col indexes
                    Dim ordinal_SomeId As Integer = reader.GetOrdinal("someID")
                    Dim ordinal_SomeName As Integer = reader.GetOrdinal("someName")

                    While reader.Read()
                        Dim ci As CategoryInfo = New CategoryInfo(reader.GetInt32(ordinal_SomeId), reader.GetString(ordinal_SomeName))
                        records.Add(ci)
                    End While

                    Return records

                End Using
            End Using
        End Using
    End Function

您可以尝试类似上面的操作,using 语句将处理连接关闭和对象处置。 当类实现 IDisposable 时,此功能可用。 还构建并返回 CategoryInfo 的 IList。

Public Function GetSizeInfoBySite(ByVal siteID As String) As IList(Of CategoryInfo)
        Dim strSQL As String = "YES INLINE SQL!! :)"

        'reference the 2.0 System.Configuration, and add a connection string section to web.config
        '  <connectionStrings>
        '   <add name="somename" connectionString="someconnectionstring" />
        '  </connectionStrings >

        Using cn As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("somename").ConnectionString

            Using cmd As New SqlCommand(strSQL, cn)

                cmd.Parameters.Add(New SqlParameter("@MySiteID", SqlDbType.NVarChar, 2)).Value = siteID
                cn.Open()

                Using reader As IDataReader = cmd.ExecuteReader()

                    Dim records As IList(Of CategoryInfo) = New List(Of CategoryInfo)

                    'get ordinal col indexes
                    Dim ordinal_SomeId As Integer = reader.GetOrdinal("someID")
                    Dim ordinal_SomeName As Integer = reader.GetOrdinal("someName")

                    While reader.Read()
                        Dim ci As CategoryInfo = New CategoryInfo(reader.GetInt32(ordinal_SomeId), reader.GetString(ordinal_SomeName))
                        records.Add(ci)
                    End While

                    Return records

                End Using
            End Using
        End Using
    End Function

You could try something like the above, the using statements will handle connection closing and object disposal. This is available when the class implements IDisposable. Also build and return your IList of CategoryInfo.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文