国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數(shù)據(jù)庫 > SQL Server > 正文

剖析SQL Server 2005查詢通知之基礎(chǔ)篇

2024-08-31 00:45:49
字體:
供稿:網(wǎng)友

在本系列文章中,我們將深入探討如何把.NET 2.0和SQL Server 2005的查詢通知特征聯(lián)合起來,以便通知應(yīng)用程序何時關(guān)鍵數(shù)據(jù)發(fā)生變化進(jìn)而達(dá)到消除反復(fù)查詢數(shù)據(jù)庫的目的。

一、引言

數(shù)據(jù)庫應(yīng)用程序的典型問題之一是更新陳舊的數(shù)據(jù)。

設(shè)想有一個典型的顯示產(chǎn)品及其分類的電子商務(wù)網(wǎng)站。一個供應(yīng)商的產(chǎn)品列表很可能并不經(jīng)常發(fā)生變化,而其分類列表甚至更不會頻繁更改。然而,在用戶每次瀏覽該網(wǎng)站時,必須從數(shù)據(jù)庫中反復(fù)查詢這些列表。這顯然是一種典型的低效資源利用,開發(fā)者和架構(gòu)師都在絞盡腦汁想辦法以減少這種浪費(fèi)。

緩沖技術(shù)正是“最小化”對這種幾乎“停滯”的數(shù)據(jù)進(jìn)行重復(fù)查詢的技術(shù)之一。這種數(shù)據(jù)可以被進(jìn)行一次性查詢并存儲在一個緩沖區(qū)中,而且應(yīng)用程序可以從緩存中重復(fù)地存取數(shù)據(jù)。偶爾情況下,才更新緩存以得到新數(shù)據(jù)。但是,圍繞更新緩存的時間調(diào)度方面出現(xiàn)了幾個問題。該多長時間操作一次呢?例如,你每隔多長時間希望你的產(chǎn)品分類改變一次?每隔幾個月一次?每隔兩個月刷新一次該緩沖區(qū)如何?你知道會發(fā)生什么嗎?就在你刷新緩存之后,分類被更新,而且在下一次刷新前在兩個月的時間里它將保持陳舊。

查詢通知,是微軟的ADO.NET和SQL Server小組協(xié)作開發(fā)的新成果。簡言之,查詢通知允許你緩沖數(shù)據(jù)并且僅在SQL Server中的數(shù)據(jù)發(fā)生變化時才發(fā)出通知。一旦接到通知,你就可以刷新你的緩沖區(qū)或者采取你需要的任何措施。

在SQL Server 2005中引入的一種新特征“Service Broker”使得查詢通知成為可能。Service Broker把隊列機(jī)制引入到數(shù)據(jù)庫管理中,它使用一組隊列與服務(wù)進(jìn)行通訊,而服務(wù)反過來也知道如何往回通訊以調(diào)用相應(yīng)的實體。其實,這些隊列和服務(wù)都是一些與表、視圖和存儲過程一樣的類對象。盡管完全可以在SQL Server內(nèi)使用Service Broker,但是ADO.NET知道如何與Service Broker進(jìn)行通訊以觸發(fā)這種機(jī)制并且從Service Broker中檢索回通知。

注意 當(dāng)SQL Server中的數(shù)據(jù)發(fā)生改變時,查詢通知允許你緩沖數(shù)據(jù)并且通知你。

在.NET一端,存在很多種“鉤入”這種功能的方式。ADO.NET 2.0提供了System.Data.SqlClient.SqlDependency和System.Data.Sql.SqlNotificationRequest類。SqlDependency是SqlNotificationRequest的一種高級實現(xiàn),并且是當(dāng)使用ADO.NET 2.0時你最有可能使用的類。ASP.NET 2.0也通過System.Web.Caching.SqlCache-Dependency類(它提供了一個針對SqlDependency的包裝器)與Service Broker進(jìn)行通訊,而且這是直接通過在一個ASP.NET頁面中使用<%OutputCache>指令以聲明方式提供的功能實現(xiàn)的。這允許ASP.NET開發(fā)者容易地實現(xiàn)使依賴于SQL Server中的數(shù)據(jù)中的緩存無效。

二、.NET與Service Broker的通訊

上面這些技術(shù)是如何聯(lián)合到一起來解決“緩沖之謎”的呢?盡管你可以采取很多的措施以允許SQL Server把服務(wù)提供給.NET;但是,關(guān)鍵還在于,發(fā)送到SQL Server的查詢具有一個依附到它們的標(biāo)志以便告訴SQL Server,除了返回結(jié)果集外,SQL Server還應(yīng)該把該查詢(及其請求者)注冊到Service Broker。為此,你要創(chuàng)建一個感知該查詢的隊列和一個依附到該隊列的服務(wù),并且知道如何返回到客戶端。如果該結(jié)果集中的任何一行在數(shù)據(jù)庫中得到更新,那么在相關(guān)隊列中的項將觸發(fā),并且反過來,把一條消息發(fā)送到它的服務(wù),然后把一個通知發(fā)送回初始化該請求的應(yīng)用程序。

圖1是SQL Server Management Studio的一個快照,它顯示了在數(shù)據(jù)庫的Service Broker部分中的隊列(Queues)和服務(wù)(Services)。

圖1.該圖顯示了.NET的查詢通知所使用的Pubs數(shù)據(jù)庫中的缺省隊列和服務(wù)。

下面是理解這一過程的一些有關(guān)重要內(nèi)容:

· 存在一些規(guī)則以指出SQL Server接收哪些類型的查詢。

· 一旦SQL Server發(fā)送回通知,隊列和服務(wù)即被刪除。這意味著,你僅能在每次請求中得到一個通知。一個典型的應(yīng)用程序會重新查詢數(shù)據(jù)庫并且,在同時,請求在Service Broker中創(chuàng)建一種新的依賴性。

· 返回到應(yīng)用程序的信息也不過是“something changed”。該應(yīng)用程序并不被通知改變了什么(請參考本文中的SQLNotificationEventArgs
節(jié)了解更多的信息)。

· 盡管依賴性被綁定到從查詢中返回的行上;但是,它并不被查詢中的單個列加以過濾。如果你有一個查詢—它返回你的組織的基本成員姓名以及那些單個改變之一的地址(但是,其姓名并不改變),這將觸發(fā)一個改變通知。很希望,這種特殊行為在未來的版本中會有所改變。

· 通知被返回,通過一個專門針對這一目的建立的SqlConnection。這個連接并不加入連接池中。

三、何時使用查詢通知

查詢通知是針對于并不經(jīng)常改變的數(shù)據(jù)而設(shè)計的。最好把它應(yīng)用于服務(wù)器端的應(yīng)用程序(例如ASP.NET或remoting)而不是客戶端應(yīng)用程序(例如Windows表單應(yīng)用程序)。記住,每一個通知請求都要在SQL Server中注冊。如果你擁有大量的都有通知請求的客戶端應(yīng)用程序,那么這可能會導(dǎo)致你的服務(wù)器產(chǎn)生資源問題。微軟推薦,對于客戶端應(yīng)用程序,你應(yīng)該限制查詢通知使用為不多于十個并行用戶。

對于大規(guī)模應(yīng)用程序來說,查詢通知可能是一種強(qiáng)有力的幫助,而不用簡單地添加越來越多的服務(wù)器以滿足要求。設(shè)想,有一家大型的為成千上百萬用戶提供在線軟件更新服務(wù)的軟件公司。不是使每一個用戶的更新操作都觸發(fā)服務(wù)器上的另一個查詢來確定需要哪些組件,而是能夠緩沖查詢結(jié)果并且可以直接從該緩存中服務(wù)匹配的查詢。

注意:對于客戶端應(yīng)用程序來說,應(yīng)該限制你的查詢通知使用—不多于十個并發(fā)用戶。

對于較小規(guī)模的情況而言,下拉式列表框是另一種典型的數(shù)據(jù)集;此時該數(shù)據(jù)集更新的次數(shù)并不如請求的次數(shù)多。產(chǎn)品列表、州列表、國家列表、供應(yīng)商、銷售人,甚至更多不太需要頻繁改變的信息正是使用通知的較好候選。

四、為使用查詢通知作準(zhǔn)備

因為默認(rèn)情況下SQL Server 2005處于高度安全的狀態(tài),所以你需要“打開”一些功能才能使用查詢通知。首先,你要使用的每一個數(shù)據(jù)庫都需要啟動Service Broker功能。為此,你可以在T-SQL中使用如下命令實現(xiàn):

USE mydatabase

ALTER DATABASE mydb SET ENABLE_BROKER

另外,你需要授予一些SQL Server權(quán)限以允許非管理員帳戶能夠參與使用查詢通知。

五、SqlDependency.Start和Stop

SqlDependency和SqlCacheDependency都要求,在任何通知請求前先調(diào)用靜態(tài)方法SqlDependency.Start()。這個方法負(fù)責(zé)創(chuàng)建一個SqlConnection以實現(xiàn)在數(shù)據(jù)改變時接收通知。注意,你僅需要在一個應(yīng)用程序的生命周期的開始建立這些內(nèi)容。例如,在一個ASP.NET應(yīng)用程序中,global.asax文件的Application_Start事件處理器就是實現(xiàn)這一功能的好地方。

注意,對包含在通知中的每一個連接都應(yīng)該調(diào)用Start方法。因此,如果你在應(yīng)用程序中存取多個數(shù)據(jù)庫,那么你需要為每一個數(shù)據(jù)庫調(diào)用Start。在下列示例中,有一個針對Pubs數(shù)據(jù)庫的連接串pubsConn,它在這個應(yīng)用程序的web.config文件中定義。

為了切斷這個連接,你可以使用SqlDependency.Stop(),這也是一個靜態(tài)方法。

以下為引用的內(nèi)容:
Sub Application_Start(ByVal sender as Object, _
ByVal e as EventArgs)
System.Data.SqlClient.SqlDependency.Start _
(System.Configuration.ConfigurationManager. _
Connectionstrings("pubsConn").ConnectionString)
End Sub
Sub Application_End(ByVal sender as Object,
ByVal e as EventArgs)
System.Data.SqlClient.SqlDependency.Stop _
(System.Configuration.ConfigurationManager. _
Connectionstrings("pubsConn").ConnectionString)
End Sub

如果你在調(diào)用Start和Stop的同時觀察SQL Server Profiler,那么你會看到許多有趣的信息。當(dāng)調(diào)用Start時,應(yīng)用程序運(yùn)行一個查詢以確保支持Service Broker,然后創(chuàng)建一個存儲過程備以后用于清除在Service Broker基礎(chǔ)結(jié)構(gòu)中的SqlDependency隊列和服務(wù)。最后,它運(yùn)行一個SQL Server 2005 WaitFor命令,該命令負(fù)責(zé)查詢在Notification Service部分的入口。這就是如果你使用ADO.NET的低級SqlNotificationRequest對象的話所有你需要顯式完成的事情。

在整個的.NET 2.0的設(shè)計過程中,SqlDependency底層架構(gòu)從一種推模式(來自SQL Server)改變?yōu)橐环N拉模式(來自.NET)。這樣做的原因是為了解決第一次設(shè)計時所導(dǎo)致的一些安全問題。微軟的Sushil Chordia在MSDN上發(fā)表了一篇有關(guān)于這種改進(jìn)的文章,該文詳細(xì)描述了這一改進(jìn)的內(nèi)在機(jī)理。

六、你的第一個通知

下面,讓我們開始使用SqlDependency來分析一下所有上面這些是如何協(xié)同工作的。
首先,我們創(chuàng)建一個類NotificationTest來存取你的數(shù)據(jù)。在這個類中,還要創(chuàng)建一個典型的函數(shù)以便從Pubs數(shù)據(jù)庫的Authors表中查詢一些數(shù)據(jù)并返回一個SqlDataReader。

以下為引用的內(nèi)容:
Imports System.Data.SqlClient
Public Class NotificationTest
Public Function DepTest() As SqlDataReader
Dim conn As New SqlConnection(connstring)
conn.Open()
Dim cmd As New SqlCommand(
"SELECT * FROM authors(", conn)")
Dim rdr As SqlDataReader
rdr = cmd.ExecuteReader()
Return rdr
End Function
End Class

現(xiàn)在,讓我們修改代碼來加入這種依賴性。首先,聲明一個名為SqlDependency的對象。為了使之用于該類中的其它函數(shù)中,我把它定義為一個類變量。

然后,你需要改變這個查詢。查詢通知要求你顯式地列舉在你的查詢中的列,以及總是使用一種“兩部分”的表名。注意一下在修改后的代碼示例中的新的查詢文本。

然后,實例化新的SqlDependency并且把它依附到命令中。

就是這些。當(dāng)執(zhí)行命令時,依賴性隨著它直到數(shù)據(jù)庫。在它處理查詢的同時,SQL Server能夠看到這一依賴性并且把它發(fā)送到Service Broker以注冊它。

以下為引用的內(nèi)容:
Imports System.Data.SqlClient
Public Class NotificationTest
Dim dep As SqlDependency
Public Function DepTest() As SqlDataReader
Dim conn As New SqlConnection(connstring)
conn.Open()
Dim cmd As New SqlCommand( _
"SELECT au_id, au_lname,au_fname " & _
"FROM dbo.authors", conn)
dep = New SqlDependency(cmd)
Dim rdr As SqlDataReader
rdr = cmd.ExecuteReader()
Return rdr
End Function
End Class

現(xiàn)在,你已經(jīng)注冊了依賴性,但是當(dāng)通知返回到應(yīng)用程序時你還根本沒有捕獲它。不過,SqlDependency類提供了兩種方式來了解一個通知。一種方式是通過OnChange事件,你可以通過創(chuàng)建一個代理來捕獲它;另一種方式是通過屬性HasChanges,你可以在你的應(yīng)用程序邏輯中對之進(jìn)行測試。在下列代碼中,我在OnDepChange事件中添加了代碼以便在后面的某個時候測試通知。

以下為引用的內(nèi)容:

Imports System.Data.SqlClient
Public Class NotificationTest
Dim dep As SqlDependency
Public Function DepTest() As SqlDataReader
Dim conn As New SqlConnection(connstring)
conn.Open()
Dim cmd As New SqlCommand( _
"SELECT au_id,au_lname,au_fname FROM " _
"dbo.authors", conn)
dep = New SqlDependency(cmd)
AddHandler dep.OnChange, AddressOf OnDepChange
Dim rdr As SqlDataReader
rdr = cmd.ExecuteReader()
Return rdr
End Function
'處理器方法
Public Sub OnDepChange(ByVal sender As Object, _
ByVal e As SqlNotificationEventArgs)
Dim DepInfo As String = e.Info.ToString
'做一些事情以響應(yīng)通知
End Sub
Public ReadOnly Property HasChanges() As Boolean
Get
Return dep.HasChanges
End Get
End Property
End Class

現(xiàn)在,我們來看一下其工作原理。首先,把一個斷點(diǎn)放到OnDepChange事件的End Sub代碼行。然后,從你喜歡的網(wǎng)頁、表單程序或控制臺程序中調(diào)用DepTest函數(shù)來進(jìn)行測試。在返回SqlDataReader后,在Visual Studio 2005的Server Explorer或在SQL Server Management Studio中打開Authors表并且編輯某一個字段內(nèi)容。例如,一旦鎖定這一改變,那么,當(dāng)你把光標(biāo)移動到表中的一個新行時,斷點(diǎn)應(yīng)該被激活。

七、SQLNotificationEventArgs

當(dāng)你看到通知的確從數(shù)據(jù)庫中傳來時,你可以分析一下相應(yīng)變量的值,它是一個SqlNotificationEventArgs對象。SqlDependency總是隨著OnChange事件返回這個對象,而且它是很有用的。其中,SqlNotificationInfo是一個具有18種可能值的枚舉類型。其中,一些值對應(yīng)情況正常,而另一些顯示出了問題。這些枚舉中有Update,Insert和Delete—告訴你在數(shù)據(jù)中發(fā)生了什么類型的變化。還有其它一些值即使在事件發(fā)生時也不會被發(fā)送。例如,重新啟動服務(wù)器將激發(fā)所有的通知;而枚舉值Drop或Truncate告訴你已經(jīng)對依賴的表實現(xiàn)了某種操作。

另外,還存在一些依賴性甚至還不能被注冊的情形,例如如果你試圖對一個UPDATE查詢設(shè)置一個依賴性將返回Invalid。而返回值Query顯示你的查詢語法并不符合通知的嚴(yán)格規(guī)則。上面枚舉表中的最后兩個枚舉值,還有其它幾個與不能注冊查詢相關(guān)的枚舉值在執(zhí)行該命令時被立即返回。

通過查找MSDN庫中的有關(guān)SqlNotificationInfo枚舉文檔,你可以得到這些枚舉的完全列表。

當(dāng)我一些場合上談?wù)摬樵兺ㄖ獣r,人們總是問我:“通知是否會告訴你發(fā)生了什么事情?”。回答是“不會”。

總之,SQLNotificationEventArgs能夠向你給出一個通知中最為詳細(xì)的信息,而這些信息在調(diào)試排錯時是非常有用的。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 喀什市| 新绛县| 陆良县| 新巴尔虎左旗| 娱乐| 肥城市| 英德市| 昂仁县| 雷波县| 徐闻县| 年辖:市辖区| 阳西县| 西林县| 池州市| 靖宇县| 会理县| 大渡口区| 云浮市| 永川市| 太仓市| 邳州市| 鄱阳县| 常德市| 兴和县| 钦州市| 天全县| 舒城县| 博罗县| 洛阳市| 乡宁县| 论坛| 岗巴县| 安康市| 交城县| 苍南县| 咸丰县| 上栗县| 阜南县| 聂荣县| 六安市| 商都县|