我的SQLCommand + ExecuteScalar / ExecuteReader如何可以从另一个调用中返回结果?

时间:2011-08-01 11:35:08

标签: sql multithreading sql-server-2008

我有两段代码似乎正在经历只能被描述为多线程问题的代码。

我不相信我已经编写了任何多线程代码,但我的代码在网络服务器的上下文中运行,因此多线程基本上是生态系统的一部分。

该代码基于SQL,使用ADO.Net。

(注意:我很欣赏SQL注入攻击的可能性,但是现在让我们假设这是因为这些SQL命令的SQL不能直接受到用户输入的影响)

GetField 采用SQLConnection和一些SQL。

  • 它假设SQL的结构为“从SomeTable中选择前1个SomeField ”。
  • 它围绕此SQL
  • 创建一个SQLCommand
  • 执行命令的ExecuteScalar函数。
  • 返回ExecuteScalar
  • 提供的值

GetRecord 同样采用SQLConnection和一些SQL。

  • 它假定SQL的结构为“从SomeTable中选择 SomeFields ”。
  • 执行命令的ExecuteReader函数。
  • 它将ExecuteReader提供的结果解析为已知结构
  • 返回已知结构

问题我遇到的是,偶尔GetRecord中的ExecuteReader函数似乎正在检索GetField所期望的结果

然后尝试将数据解析为已知结构。

我无法可靠地重现这一点,因此我正在寻求帮助。

有没有人有任何想法可能会发生这种情况?

FWIW我的后端SQL是SQL2008

更新: FWIW,拥有这些方法的对象,有自己的连接字段,初始化为新的SQLConnection对象,该对象本身从中心位置提供连接字符串。

更新:这是我正在谈论的那种DA对象的示例。


Imports System.Data.SqlClient
Public Module SomeModule
    Public Function GlobalConnection() As SqlConnection
        Return New SqlConnection(GetSQLStringFromConfig())
    End Function
End Module
Public Class ExampleDA
    Protected Con As SqlConnection
    Public Sub New()
        Me.Con = GlobalConnection()
    End Sub
    Public Function GetRecord(ByVal SQL As String) As String()
        Dim Close As Boolean = EnsureConnectionOpen(Con)
        Dim dc As New SqlCommand(SQL, Con)
        Try
            Dim DcExecuteReader As SqlDataReader
            If Close Then
                DcExecuteReader = dc.ExecuteReader(CommandBehavior.CloseConnection)
            Else
                DcExecuteReader = dc.ExecuteReader()
            End If
            ' ToStringArray doesn't exist but it gets the general point across.
            Return DcExecuteReader.ToStringArray() 
        Catch ex As SqlException
            Throw
        End Try
    End Function

    Public Function GetField(ByVal SQL As String, ByVal DefaultValue As Object) As Object
        Dim Close As Boolean = EnsureConnectionOpen(Con)
        Dim dc As SqlCommand = New SqlCommand(SQL, Con)
        Dim Result As Object = GetField(dc, DefaultValue)
        If Close Then Con.Close()
        Return Result
    End Function

    Private Function GetField(ByVal Command As SqlCommand, Optional ByVal DefaultValue As Object = Nothing) As Object
        Try
            Dim ReturnValue As Object
            Dim Close As Boolean = EnsureConnectionOpen(Command.Connection)
            ReturnValue = Command.ExecuteScalar()
            If ReturnValue Is Nothing Then
                ReturnValue = DefaultValue
            End If
            If Close Then
                Command.Connection.Close()
            End If
            If IsDBNull(ReturnValue) Then
                Return DefaultValue
            Else
                Return ReturnValue
            End If
        Catch ex As Exception
            Debug.WriteLine(ex.ToString)
            Throw
        End Try
    End Function
    Private Function EnsureConnectionOpen(ByRef Con As SqlConnection) As Boolean
        If Con.State <> ConnectionState.Open Then
            Con.Open()
            Return True
        End If
        Return False
    End Function
End Class

4 个答案:

答案 0 :(得分:1)

您如何处理数据库的连接?

一个数据库连接= SQL的一个进程,无论如何都不会共享这些进程。要获得“混合”结果,您需要覆盖共享连接的某些上下文。

换句话说,SQLConnection is not thread safe

答案 1 :(得分:0)

如何在函数之间存储/共享连接?

你在MARS下运行吗?如果没有,请尝试在连接字符串中启用它(MultipleActiveResultSets = True)。

请注意,IIS可能/将在执行期间将执行上下文从一个线程切换到另一个线程。因此,任何共享连接最终将在两个线程之间共享,并且可能会失败。使用MARS和/或明确的新连接应该可以缓解这种情况。

答案 2 :(得分:0)

您必须同时使用一个连接,否则您可能会得到不需要的结果。假设有人在连接上打开一个事务而没有其他功能知道?

您应该始终调用GetConnection,因为后端无论如何都会进行连接池化。因此,在性能方面,它很可能无关紧要。

HTH

马里奥

答案 3 :(得分:0)

好的,那是在惹麻烦!沿着这些方向重写你的GetXXX方法(对不起C#语法,但我不熟悉VB ;-))

GetField( string sqlCommand )
{
   SqlConnection conn = new SqlConnection( connectionString );
   conn.Open();

   try
   {
       using ( SqlCommand cmd = conn.CreateCommand() )
       {
           cmd.CommandText = cmd;

           cmd.ExecuteScalar();


           //here be your code..

       }

   }
   finally
   { conn.Close();
   }
}

不要存储连接,不要对它们做任何事情。根据需要打开和关闭,库在幕后执行命令汇集!

HTH

马里奥