2013-04-15 38 views
4

的SqlDependency正常工作,並代理隊列和服務得到適當的下降,當應用程序存在(我做執行SqlDependency.Stop(...)爲終止之前,建議進程),但我注意到在應用程序關閉後,由SqlDependency創建的通知訂閱存在於表「sys.dm_qn_subscriptions」中。的SqlDependency訂閱不會從dm_qn_subscriptions在關機下降

如果我以後(應用程序後關機)執行的條件,應該讓這個訂閱火,它似乎火,因爲SQL Server將記錄在事件查看器中的信息的消息,大意是:

The query notification dialog on conversation handle '{3F03B693-C0A5-E211-A97B-E06995EBDB20}.' closed due to the following error: ' -8490 Cannot find the remote service 'SqlQueryNotificationService-0ea1f686-e554-4e25-aa7d-4f6d85171cc3' because it does not exist.'.

然後從「sys.dm_qn_subscriptions」中刪除訂閱。

注意:當應用程序處於活動狀態時,訂閱也會正常啓動。就我的應用程序而言,沒有任何錯誤,但它讓我擔心,一旦它們所依賴的代理隊列/服務被終止,訂閱就不會自動在數據庫系統表中被清除。這可以導致(至少)在數據庫中累積豐富的幻像/不死的訂閱記錄,並導致事件查看器中不必要的SQL Server清理消息(每個應用程序運行都會在「sys.dm_qn_subscriptions」中生成新的不連續記錄)。

這種行爲是否正常?事情可以做得更整潔嗎?

由於提前,

D.

回答

4

這是正常行爲。 QN是長期存在的,它們會在數據庫重新啓動時觸發(因此在服務器重啓後也會觸發)。但是SqlDependency設置了一個臨時服務/隊列來接收通知,並且這些應該在崩潰的情況下通過使用dialog timerinternal activation來拆除。這兩種機制相互作用的方式就是你所看到的ERRORLOG污染。沒有什麼不好發生,at least not usually,但顯然不是整齊。

Can things be made neater?

您可以直接使用SqlNotificationRequest不再提供創建服務/隊列收到您的應用程序域的通知,並將其路由到適當的SqlDependency.OnChange事件的「服務」推出自己的解決方案。根據具體情況,有可行的替代方案。但是是相當低的水平的工作,你可能最終解決一個糟糕的方式的問題比原來SqlDependency解決方案......

BTW沒有辦法「降」的應用程序退出掛起QN訂閱。這個問題是由QN用作通知傳遞機制的單向對話所固有的。正確的通知(訂閱)應該由訂閱者發起,並且通知應該是從目標(通知者)回到發起者(訂閱者)的響應消息。

+0

非常感謝您的回覆,Remus!我真的很想知道我怎麼才能明確地注意到這個問題,因爲你的名字總是與Interweb上的SqlDependency建議有關: 另外一個問題,如果我可以的話:如果這是預期的行爲,我不希望重新實現SqlDependency,那麼我的最佳策略是讓SQL Server清理服務變得不那麼健談?任何準備使用的線索?如果不是,不用擔心:我會自己做一些額外的工作。 再次感謝和歡呼! – DP2010

+0

'只是讓SQL Server清理服務變得不那麼煩瑣'恐怕這是不可能的... –

+0

嗯,太糟糕了......然後再次感謝! – DP2010

0

如果你不介意一點點cheezy,我已經找到一種方法來清理這些了退出......

首先,設置了onDependencyChange可以觀察讓它知道標誌不是重新訂閱查詢。

其次,設置標誌並執行您知道會觸發依賴項訂閱的「不做任何更新」。

update foo_master set foo_bar = foo_bar where foo_id = @id; 

我的依賴關係監視是在單獨的行上完成的,所以我只需要撓一行就可以觸發它。這可能不是您想要在大型結果集上執行的操作。

在我的FormClosing事件中,我在斷開連接之前觸發每個依賴關係。

部分代碼:

Private _dependency As SqlDependency = Nothing 
Private _beingKilled = False 

' dependency is set up in loadRecord(ByVal idRow as Integer) 

Private Sub onDependencyChange(ByVal sender As Object, ByVal e As SqlNotificationEventArgs) 
    ' This event may occur on a thread pool thread; It is illegal to update the UI from a worker thread. 
    ' The following code checks to see if it is safe update the UI. 
    Dim iSync As ISynchronizeInvoke = CType(_connection.masterForm, ISynchronizeInvoke) 

    ' If InvokeRequired returns True, the code is executing on a worker thread. 
    If iSync.InvokeRequired Then 
     Dim tempDelegate As New OnChangeEventHandler(AddressOf onDependencyChange) ' Create a delegate to perform the thread switch 
     Dim args() As Object = {sender, e} 
     iSync.BeginInvoke(tempDelegate, args) ' Marshal the data from the worker thread to the UI thread. 
    Else 
     RemoveHandler _dependency.OnChange, AddressOf onDependencyChange 
     If Not _beingKilled Then loadRecord(_id) 
    End If 
End Sub 

然後,只需設置_beingKilled爲True並執行什麼也不做更新。

+0

或者,另一種方式是刪除處理程序,然後剔除訂閱...例如,如果您要訂閱新行,請移除處理程序,癢癢舊行,然後訂閱新的查詢。退出時,放下處理程序,癢癢舊的行並訂閱新的東西。 –