【问题标题】:Check if ADODB connection is open检查 ADODB 连接是否打开
【发布时间】:2013-07-12 09:20:11
【问题描述】:

我在一些 excel 程序中使用以下内容来建立与我们数据库的连接。

Private Const strConn As String = _
    "PROVIDER=SQLOLEDB.1 ..."     

Sub OpenConnection()

Set cn = CreateObject("ADODB.Connection")
cn.Open strConn
cn.CommandTimeout = 0
Set rs = CreateObject("ADODB.Recordset")
Set rs.ActiveConnection = cn

End Sub 

在随后的代码中,我使用各种 SQL 字符串打开连接。
我想测试rs 是否打开,所以我知道它需要关闭,但以下不起作用。如何更改以下条件以使其正常工作?

If (rs.Open = True) Then
    rs.Close
End If

以下工作,但我宁愿不以这种方式使用错误捕获:

On Error Resume Next
    rs.Close

【问题讨论】:

    标签: vba oledb


    【解决方案1】:

    ADO Recordset 有.State 属性,你可以检查它的值是adStateClosed 还是adStateOpen

    If Not (rs Is Nothing) Then
      If (rs.State And adStateOpen) = adStateOpen Then rs.Close
      Set rs = Nothing
    End If
    

    MSDN about State property

    编辑; 不检查 .State 与 1 或 0 的原因是因为即使它在 99.99% 的时间内都有效,仍然有可能拥有 other flags set,这将导致 If 语句无法通过 adStateOpen 检查。

    编辑2:

    对于没有引用 ActiveX 数据对象的后期绑定,您几乎没有选择。 使用 ObjectStateEnum 中的 adStateOpen 常量的值

    If Not (rs Is Nothing) Then
      If (rs.State And 1) = 1 Then rs.Close
      Set rs = Nothing
    End If
    

    或者您可以自己定义常量以使您的代码更具可读性(将它们全部定义为一个很好的示例。)

    Const adStateClosed As Long = 0 'Indicates that the object is closed.
    Const adStateOpen As Long = 1 'Indicates that the object is open.
    Const adStateConnecting As Long = 2 'Indicates that the object is connecting.
    Const adStateExecuting As Long = 4 'Indicates that the object is executing a command.
    Const adStateFetching As Long = 8 'Indicates that the rows of the object are being retrieved.    
    
    [...]
    
    If Not (rs Is Nothing) Then
    
        ' ex. If (0001 And 0001) = 0001 (only open flag) -> true
        ' ex. If (1001 And 0001) = 0001 (open and retrieve) -> true
        '    This second example means it is open, but its value is not 1
        '    and If rs.State = 1 -> false, even though it is open
        If (rs.State And adStateOpen) = adStateOpen Then 
            rs.Close
        End If
    
        Set rs = Nothing
    End If
    

    【讨论】:

    • 好的 - 只是猜测,但答案中有错字吗? ...让我尝试编辑...应该是If (rs.State And rs.adStateOpen) = rs.adStateOpen Then :虽然我仍然不明白这个条件语句。如果 rs 是开放的,它将评估什么? If (1 And ?) = ? Then
    • 按位运算And。只有当.State 中的那个位被置位并且所有其他位都被置零时,adStateOpen 的位才会保持置位。将And 操作值与adStateOpen 进行比较的结果只有在.State 中设置了该位标志时才会产生True
    • 嘿,你的困惑可能已经到位。我不是有意使用rs.adStateOpen,而是adStateOpen
    • 不,就像我说的那样,它在大多数情况下都可以使用,但是您最终可能会同时打开它并执行命令或获取行,在这种情况下 .State 值会是1+4=5(binary 0101)1+8=9(binary 1001)。如果你愿意,你可以使用简单的If rs.State = 1,但为什么不以正确的方式使用它,它适用于所有情况,没有未来难以发现的错误情况。
    • 是的,ADODB.Connection.State 也使用ObjectStateEnum
    【解决方案2】:

    这是一个老话题,但万一其他人还在寻找......

    我在取消停靠事件后遇到了麻烦。即使在重新连接到网络之后,保存在全局对象中的打开的数据库连接也会出错。这是由于远程主机强制终止 TCP 连接。 (错误-2147467259:TCP Provider:现有连接被远程主机强行关闭。)

    但是,错误只会在尝试第一次交易之后显示出来。到目前为止,Connection.State 和 Connection.Version(根据上述解决方案)都不会显示任何错误。

    所以我写了下面的小子来强制错误 - 希望它有用。

    我的设置(Access 2016,SQL Svr 2008R2)的性能测试每次调用大约需要 0.5 毫秒。

    Function adoIsConnected(adoCn As ADODB.Connection) As Boolean
    
        '----------------------------------------------------------------
        '#PURPOSE: Checks whether the supplied db connection is alive and
        '          hasn't had it's TCP connection forcibly closed by remote
        '          host, for example, as happens during an undock event
        '#RETURNS: True if the supplied db is connected and error-free, 
        '          False otherwise
        '#AUTHOR:  Belladonna
        '----------------------------------------------------------------
    
        Dim i As Long
        Dim cmd As New ADODB.Command
    
        'Set up SQL command to return 1
        cmd.CommandText = "SELECT 1"
        cmd.ActiveConnection = adoCn
    
        'Run a simple query, to test the connection
        On Error Resume Next
        i = cmd.Execute.Fields(0)
        On Error GoTo 0
    
        'Tidy up
        Set cmd = Nothing
    
        'If i is 1, connection is open
        If i = 1 Then
            adoIsConnected = True
        Else
            adoIsConnected = False
        End If
    
    End Function
    

    【讨论】:

      【解决方案3】:

      这个话题很老,但如果像我这样的其他人搜索解决方案,这是我找到的解决方案:

      Public Function DBStats() As Boolean
          On Error GoTo errorHandler
              If Not IsNull(myBase.Version) Then 
                  DBStats = True
              End If
              Exit Function
          errorHandler:
              DBStats = False  
      End Function
      

      所以“myBase”是一个数据库对象,我已经创建了一个类来访问数据库(带有插入、更新等的类),并且在模块上,该类使用在对象中声明(显然),我可以使用“[对象].DBStats”测试连接:

      Dim BaseAccess As New myClass
      BaseAccess.DBOpen 'I open connection
      Debug.Print BaseAccess.DBStats ' I test and that tell me true
      BaseAccess.DBClose ' I close the connection
      Debug.Print BaseAccess.DBStats ' I test and tell me false
      

      编辑:在 DBOpen 我使用“OpenDatabase”,在 DBClose 我使用“.Close”和“set myBase = nothing” 编辑2:在函数中,如果你没有连接,.version 会给你一个错误,所以如果没有连接,errorHandler 会给你错误

      【讨论】:

      • 这是什么:.Version? ....你可以在myClass 中添加代码 ....我最近发布了这个,就在前一周,所以我很想看看你是如何写的myClasscodereview.stackexchange.com/questions/116253/…
      • ".Version" 为您提供数据库的版本,因此如果您不连接到数据库(我使用 Access),您将无法知道版本,因此您可以通过这种方式知道您是否正在连接到数据库
      • 这让我走上了正轨,但在远程主机终止连接的情况下不起作用,因为版本仍然可用且非空。在这种情况下,可以使用我刚刚发布的解决方案。
      猜你喜欢
      • 1970-01-01
      • 2012-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-19
      • 1970-01-01
      • 2011-04-13
      • 2016-04-24
      相关资源
      最近更新 更多