GIS開發之SDE連接釋放問題

                          GIS開發之SDE連接釋放問題


往Personal GDB或SDE GDB中寫入要素記錄是一件非常簡單的事情,但似乎太多的情況下,寫入數據的用例過於簡單,使得許多代碼問題、特別是ArcSDE本身的問題和Error無法暴露,很多人也從未意識到類似的問題。我最近正在做類似的工作,代碼編寫似乎不難,但測試就要了命了,發現的問題數不勝數,頭痛不已。

1.插入記錄的效率問題
向要素類中插入記錄有兩種方式,一是IFeature.Store,另一個是IFeatureCursor.Insert(IFeatureBuffer)和IFeatureCursor.Flush方法,顯而易見的,後一種方法由於使用了緩存,速度上比前者快。

2.往MDB和SDE要素類中插入記錄
這兩種類型的要素類在往其中插入數據時不一定需要使用IWorkspaceEdit接口來開啓和關閉一個Session,但是,如果SDE的要素類被註冊爲version,這個接口就必須使用了,否則CPU會高達100%,並會爆出“the operation in invalid on a closed state”的錯誤。而使用了有版本的SDE要素類,我遇到了許多令人崩潰的SDE ERROR,比如FDO_E_SE_DB_IO_ERROR、FDO_E_SE_OUT_OF_LOCKS等等。

3.將多個MDB導入一個MDB的時候,如果使用了IWorkspaceEdit接口,會出現某幾個圖層無法用ArcMap或ArcCatalog打開的情況,即以打開程序就崩潰,而不是用該接口,其它相同的代碼做的加載過程,一切正常。

4.將兩個或以上MDB導入一個MDB時候,到第二個MDB,很可能發生“**_SHAPE_INDEX被佔用”的情況,這是因爲寫.NET平臺代碼時,你遍歷或插入數據的遊標cursor未釋放的緣故。pFeatureCursor=null;並不會將對象從內存中清除,這是因爲.NET平臺是由Runtime來收集垃圾的,不像VC或VB那樣能直接銷燬COM對象,此時你應該使用System.Runtime.InteropServices.Marshal.ReleaseComObject方法來強制釋放COM對象,以解除對某個表的獨佔狀態。

關於釋放SDE連接的問題

 如果我們嘗試往SDE中使用AO代碼加載大量的數據,比如每個圖層50萬條記錄,一共30個圖層,那麼這個過程是個不折不扣的噩夢,你會遇到許多匪夷所思的問題,一般而言,出了問題總是會報個fdoerr號,我們也可以查一查,但如果出現的問題號屬於SDE ERROR類型,就不好說了,你會發現某些情況整個網絡上都沒有看到過,就是一個孤例。比如我遇到過的FDO_E_SE_DB_IO_ERROR和FDO_E_SE_OUT_OF_LOCKS等。

我在往SDE中寫代碼導入數據時候頻繁遇到FDO_E_SE_DB_IO_ERROR問題,儘管safe網站上給出了該問題的三種可能原因,但我一直都沒能從Oracle的角度解決。統計一下往SDE導入數據成功的情況,每次導入一個要素類,即每個要素類導入時都給開啓一個專用的gsrvr進程,成功率是最高的,幾乎爲95%。 不成功的10%是一次導入200萬條標註要素類,但分開導,每次50萬條,也一切安好。

那麼問題就來了,我們知道,SDE安裝後,SDE與DBMS之間有一個giomgr進程負責管理雙方的通訊過程,即根據訪問請求建立gsrvr進程。一般地,gsrvr將處理與SDE有關的查詢,存儲,刪除等操作,並且它能處理多個連接請求,它與DBMS的關係就是“通則不痛,通則不痛”,一旦傳輸的數據量多了,gsrvr就開始抽風了。我們的問題是,如何讓一個要素類處理完成後,釋放這個連接,即關閉該gsrvr進程,在下一個要素類開始時再次建立一個新gsrvr進程。這個方式的確也是最爲保險的。

現在問題就是,如何釋放SDE連接,事實上,如果使用純COM對象來寫,這幾乎不是問題,有人認爲將工作空間對象設置爲null即可。比如我們寫個VB的代碼:
dim pFWS as IFeatureWorkspace
set pFWS=SdeWorkspaceFactory.open()   '1
set pFWS=nothing                                       '2

去看看Oracle的連接,在1執行完後,應該有兩個SDE鏈接,而在執行完2以後,就只有一個SDE鏈接了,其所有者是giomgr。顯然,SDE連接被關閉了。

那麼在.NET平臺中,這種set pFWS=nothing是行不通的,我們得使用System.Runtime.InteropServices.Marshal.ReleaseComObject(pFWS);才能讓非託管代碼在內存中被清除。試一試,也可以發現SDE的連接關閉。

將問題再複雜一點,如果我們遍歷一次pFWS中的某個要素類,會發現即使使用System.Runtime.InteropServices.Marshal.ReleaseComObject(pFWS);也搞不定,解決的方法是,將你在代碼中new出來的所有的AO對象都用System.Runtime.InteropServices.Marshal.ReleaseComObject方法釋放,某些循環產生的對象,如:
pFeature=pFeatureCursor.NextFeature();
while(pFeature!=null)
{
     System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeature);
     pFeature=pFeatureCursor.NextFeature();
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(pFeatureCursor);
也必須銷燬,如果有一個與SDE數據庫相關的對象未銷燬,則仍然存在兩個SDE連接。

使用這種一個圖層一個gsrvr進程的方法後,再未出現過FDO_E_SE_DB_IO_ERROR問題。

發佈了13 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章