检查ADODB连接是否已打开

时间:2013-07-12 09:20:12

标签: vba oledb

我在一些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

3 个答案:

答案 0 :(得分:28)

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检查。

EDIT2:

对于未引用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

答案 1 :(得分:1)

这是一个古老的话题,但是如果其他人仍在寻找...

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

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

所以我在下面写了一个小的sub来强制执行错误-希望它有用。

在我的设置(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

答案 2 :(得分:0)

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

type AB = Kleisli[Try, A, B]
type BC = Kleilsi[Try, B, C]
type CD = Kleisli[Try, C, D]

type XReader[T] = Reader[X, T]

val fooXAB: XReader[AB] = ...
val fooXBC: XReader[BC] = ...
val fooXCD: XReader[CD] = ...

val fooXAC: XReader[AC] =
  for {
    ab <- fooXAB
    bc <- fooXBC
    cd <- fooXCD
  } yield (ab andThen bc andThen cd)  

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

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

编辑:在DBOpen中我使用&#34; OpenDatabase&#34;在DBClose中我使用&#34; .Close&#34;并且&#34;设置myBase = nothing&#34; 编辑2:在函数中,如果你没有连接,.version会给你一个错误,所以如果没有连接,errorHandler会给你错误的