VBA for Excel 2016中的ADODB连接超时 – 如何检查连接是否仍处于活动状态?

我已经开发了一个小的Excel插件使用VBA直接连接到数据库。 我通过DSNbuild立了连接。 这个插件在打开它的时候很好用。 但是,一段时间后,连接到数据库似乎超时。 更准确地说,一个完全有效的查询在试图打开logging集时返回一个错误。

我的代码是这样的:

'Check Connection If Not MakeConnectionToDB Then 'Connection failed [do something] Exit Function End If 'Active connection - run the query! If Rs Is Nothing Then Set Rs = New ADODB.Recordset 'make sure its an active object If Not Rs.State = adStateClosed Then Rs.Close 'make sure its not full (throws error if a query was called before) Rs.Open strSQLQuery, CON 'Run query 

如果应用程序已打开但未使用一段时间,则rs.open语句会失败。 这是尽pipeMakeConnectionToDB UDF,看起来像这样:

 If Not ConIsActive Then 'If there is no active connection, make it so If CON Is Nothing Then 'Connection may be inactive because the object dropped, or because it timed out, or any other reason - Only recreate the object if the former is the case Set CON = New ADODB.Connection End If On Error Resume Next CON.Open strCon 'Try to connect - on error resume statement in order to ignore a connection error, that will be caught below On Error GoTo 0 Err.Clear MakeConnectionToDB = ConIsActive 'This is where a connection error will be caught if it occurred Else MakeConnectionToDB = True 'connection is active already End If 

和ConIsActive看起来像:

 Private Function ConIsActive() As Boolean 'return TRUE if there is an active connection, false otherwise Dim blnTemp As Boolean blnTemp = False If (Not (CON Is Nothing)) And (Not (CON = "")) Then If CON.State = adStateOpen Then blnTemp = True ConIsActive = blnTemp End Function 

基本上,我检查连接是否打开。 我的问题:所有这些检查返回TRUE,但连接没有打开。 如果我连接,然后离开应用程序一段时间,然后回到它,以上所有将返回连接处于活动状态,但试图用新的查询打开logging集时,将失败,可能是因为服务器closures了连接什么的。 我需要find一种方法来检查连接是否实际上能够打开一个logging集。

我可以ping服务器或什么? 我如何检查数据库是否实际返回结果给我的查询? 有没有一种方法,比只发送一个testing查询到服务器结合logging集上的error handling更高的性能? 我想这将工作,但我需要一个高性能的解决scheme,我不认为加倍的简单连接检查查询是一个优秀的解决scheme…

任何帮助表示赞赏!

你的CON对象似乎是全局范围的,打开一次,然后在你的代码中的任何地方使用,并可能在某个时候closures或不closures。

与任何支持对象的语言编写的任何代码库中的每个对象一样,数据库连接应尽可能短。

你打开它,你做你需要做的事情,然后closures它。 如果你不知道下一个命令是什么时候执行的,那么连接就没有剩余的业务了。

删除您的全局范围CON 。 用火杀死它。 连接应该是使用它的函数或过程的本地 – 它在该范围内开始,并在该范围内结束。

或者你可以封装在你自己的对象中,如果这样可以让你更容易。

 '@Folder("Data.SqlConnection") Option Explicit Private Const CONNECTION_STRING As String = "{CONNECTION STRING}" Private mConnection As ADODB.Connection Private Sub Class_Initialize() Set mConnection = New ADODB.Connection mConnection.Open End Sub Private Sub Class_Terminate() mConnection.Close Set mConnection = Nothing End Sub Public Sub ExecuteNonQuery(ByVal sql As String, ParamArray params()) With New ADODB.Command Set .ActiveConnection = mConnection Dim p As ADODB.Parameter For Each p In params .Paramaters.Append p Next .Execute End With End Sub '... 

SqlConnection类的一个实例也应该尽可能短,但是现在大部分的pipe道都被抽象掉了,所以你的调用代码可能看起来像这样:

  Const sql As String = "exec dbo.LogUserIn @userName=?, @password=?;" With New SqlConnection Dim userName As ADODB.Parameter Set userName = .CreateStringParameter(Environ$("USERNAME")) Dim password As ADODB.Parameter Set password = .CreateStringParameter(PromptForPassword) .ExecuteNonQuery sql, userName, password End With 

连接从New SqlConnection开始,干净地结束于End With ,您可以根据需要调整该SqlClass ,以支持事务,并且/或者如上所述,抽取创build参数的样板文件。

但是,这个想法仍然存在:你不创build数据库连接,并把它留在全局范围内,不知道某些代码是否可能将其设置为Nothing ,或closures它,或者启动一个从未提交的事务,或者天知道什么。

  1. 创build
  2. 打开
  3. 执行

总是。 尽可能严密。 那么你将不会有任何对象生存期问题。