Revision History:
Version
Date
Creator
Description
1.0.0.1
2003-11-15
鄭昀
草稿
Implementation Scope:
本文檔將說明出現一種不容易想到原因的訪問數據庫時發生“一般性網絡錯誤”,錯誤報告的來源是ADODB,錯誤號是“-2147467259,或者0x80004005”。
繼續閱讀之前,我們假設您熟悉以下知識:
n Microsoft SQL Server 2000
n Microsoft ADO
關鍵詞:
SQL Server、ADO、DBMSSOCN、0x80004005
現象
一天,突然有這么一個問題擺在面前:
用戶瀏覽工作流系統時,突然跑出來這么一個錯誤:
Microsoft VBScript 編譯器錯誤 錯誤 '800a03f6'
缺少 'End'
/iisHelp/common/500-100.asp,行242
Microsoft OLE DB Provider for SQL Server 錯誤 '80004005'
[DBMSSOCN]一般性網絡錯誤。請檢查網絡文檔。
/xxx/yyyframe.asp,行23
經過排查,確定真正的原因在于調用ADO連接SQL Server 2000時,發生異常,錯誤描述就是“[DBMSSOCN]一般性網絡錯誤。請檢查網絡文檔?!保劣谀莻€“Microsoft OLE DB Provider for SQL Server 錯誤 '80004005'”其實并沒有太多意義。
為什么會突然出現“[DBMSSOCN]一般性網絡錯誤?!蹦兀?BR> 服務器頁面調用的是封裝好的COM+ STA 組件,連接SQL Server 2000的其實是這個組件。
后來又提供一個比較重要的信息,當這些事情發生的時候,注意到COM+應用的進程占用了200MB的內存。
初步的猜想
以前曾經在其他地方遇到過這種錯誤。
但是,那是因為網卡或者網線閃斷(“network is down”),造成連接數據庫失敗,服務又不停地試著去連接。不知道在什么情況下,服務不斷報告:
錯誤環境說明:運行SQL命令從數據庫讀取記錄時發生COM異常;
錯誤說明:[dbmssocn]一般性網絡錯誤。請檢查網絡文檔。
錯誤號:-2147467259
“[dbmssocn]”指的是,當前用TCP/IP協議與數據庫通信。
但是,這次環境的網絡質量沒有問題。
模擬試驗
專家指出可能是因為同一臺服務器和SQL Server之間的連接都沒有Close,所以導致連接達到被允許的最大數目,從而被全部關閉。
于是我們試驗,看看一臺服務器被允許與SQL Server建立最多多少個連接。
更多信息
測試程序中重用了原工程中InitADOCmd (_Command** ppiCmd)方法。
這個方法利用ADO.Command::put_ActiveConnection方法來建立數據庫連接的:
varConn = _bstr_t("Provider=SQLOLEDB.1;……”);
hr = t_piCmd->put_ActiveConnection(varConn);
在Windows XP環境中,循環調用這個函數到了1980次,程序就出現幾秒鐘的停頓。之后,就得到0x80004005的錯誤返回值。這個值是由put_ActiveConnection方法返回的,并不是異常。所以看不到ADO異常描述。
我們通過測試程序停滯時,立刻用一個VBS腳本再次請求建立數據庫連接。于是,VBS腳本一起停滯,隔了幾秒鐘后,拋出異常,錯誤描述為:
"[DBNETLIB][ConnectionOpen (PreLoginHandshake()).]一般性網絡錯誤。請檢查網絡文檔。"
之后的1981、1982、...次put_ActiveConnectio調用,都會是同一個錯誤返回值。
在SQL Server事件探查器中,看到1980次調用之前,都只有Audit Login事件。除非關閉測試程序,才會唰地一下所有的Audit Logout事件出來了。
有時候,當第1981次建立連接的請求被SQL Server 2000認為超出允許范圍時,SQL Server 2000會主動將這一千多個的連接同時全部中斷。于是乎,在SQL Server事件探查器中,你也可以看到唰地一下所有的Audit Logout事件出來了。
如果測試程序維持著這些數據庫連接的話,內存會持續增長,如下所示:
在WinXP上(Win2000上允許連接的數目少),
情況1:
單純反復執行ADO.Command::put_ActiveConnection,則只有“Audit Login”事件,沒有Logout事件。這種請求最多達到1980之后,就會出現“一般性網絡錯誤”。
情況2:
如果是反復執行
ADO.Command::put_ActiveConnection方法,然后又執行了查詢,返回記錄集,則這種循環最多達到483之后,就會出現“一般性網絡錯誤”。
在實際測試中,第1種情況,最開始Demo用了6MB內存,最后累積的內存是:104MB。
第2種情況下,最開始Demo用了6MB內存,最后累積的內存是:39.5MB。
你可以通過下面的SQL語句察看當前與SQL Server保持的連接都來自于哪里,有多少個:
SELECT dbid,DB_NAME(dbid) as DBName,hostname,status,last_batch
FROM sysprocesses
WHERE DB_NAME(dbid)='%YourDatabaseName%' AND (last_batch > 'YY-MM-DD MM:SS:00')
ORDER BY last_batch DESC
總結:
雖然這種情況出現的比較罕見,但是如果排除了網絡質量原因,你也許可以注意一下當前服務器與SQL Server的connection數目是否維持在一個正在高漲的數量。
當連接不斷增加的時候,就要當心,服務器連接數據庫是有一定限制的,而且達到最大值后,其他程序再次請求連接時,就可能得到“一般性網絡錯誤”的警告,而且錯誤號80004005也并沒有說明到底發生了什么,SQL Server和ADO并不會告訴你連接數已經達到最大值。
Disclaimers:
本文檔所包含的信息代表了在發布之日,zhengyun對所討論問題的當前看法。本文檔不應理解為zhengyun一方的承諾,zhengyun不保證所給信息在發布之日以后的準確性。
本文檔僅供參考。
用戶必須遵守所有適用的版權法。在不對版權法所規定的權利加以限制的情況下,如未得到 zhengyun和CSDN.Net明確的書面許可,不得出于任何目的、以任何形式或手段(電子的、機械的、影印、錄制等等)復制、傳播本文的任何部分,也不得將其存儲或引入到檢索系統中。
thank tian&wu
Writen by zhengyun_ustc(at)hotmail.com