剖析SQL Server 2005查詢(xún)通知之基礎(chǔ)篇_Mssql數(shù)據(jù)庫(kù)教程
推薦:淺談Linq To Sql集成數(shù)據(jù)庫(kù)語(yǔ)言的優(yōu)劣Linq To Sql是Microsoft開(kāi)發(fā)的針對(duì)解決data!=object問(wèn)題的新技術(shù)。在筆者的一系列的文章中,對(duì)它已經(jīng)做了大量的介紹,F(xiàn)在,筆者將從經(jīng)驗(yàn)的角度,談?wù)勊膬?yōu)劣。 1、Linq To Sql的優(yōu)點(diǎn) 在Li
在本系列文章中,我們將深入探討如何把.NET 2.0和SQL Server 2005的查詢(xún)通知特征聯(lián)合起來(lái),以便通知應(yīng)用程序何時(shí)關(guān)鍵數(shù)據(jù)發(fā)生變化進(jìn)而達(dá)到消除反復(fù)查詢(xún)數(shù)據(jù)庫(kù)的目的。
一、引言
數(shù)據(jù)庫(kù)應(yīng)用程序的典型問(wèn)題之一是更新陳舊的數(shù)據(jù)。
設(shè)想有一個(gè)典型的顯示產(chǎn)品及其分類(lèi)的電子商務(wù)網(wǎng)站。一個(gè)供應(yīng)商的產(chǎn)品列表很可能并不經(jīng)常發(fā)生變化,而其分類(lèi)列表甚至更不會(huì)頻繁更改。然而,在用戶(hù)每次瀏覽該網(wǎng)站時(shí),必須從數(shù)據(jù)庫(kù)中反復(fù)查詢(xún)這些列表。這顯然是一種典型的低效資源利用,開(kāi)發(fā)者和架構(gòu)師都在絞盡腦汁想辦法以減少這種浪費(fèi)。
緩沖技術(shù)正是“最小化”對(duì)這種幾乎“停滯”的數(shù)據(jù)進(jìn)行重復(fù)查詢(xún)的技術(shù)之一。這種數(shù)據(jù)可以被進(jìn)行一次性查詢(xún)并存儲(chǔ)在一個(gè)緩沖區(qū)中,而且應(yīng)用程序可以從緩存中重復(fù)地存取數(shù)據(jù)。偶爾情況下,才更新緩存以得到新數(shù)據(jù)。但是,圍繞更新緩存的時(shí)間調(diào)度方面出現(xiàn)了幾個(gè)問(wèn)題。該多長(zhǎng)時(shí)間操作一次呢?例如,你每隔多長(zhǎng)時(shí)間希望你的產(chǎn)品分類(lèi)改變一次?每隔幾個(gè)月一次?每隔兩個(gè)月刷新一次該緩沖區(qū)如何?你知道會(huì)發(fā)生什么嗎?就在你刷新緩存之后,分類(lèi)被更新,而且在下一次刷新前在兩個(gè)月的時(shí)間里它將保持陳舊。
查詢(xún)通知,是微軟的ADO.NET和SQL Server小組協(xié)作開(kāi)發(fā)的新成果。簡(jiǎn)言之,查詢(xún)通知允許你緩沖數(shù)據(jù)并且僅在SQL Server中的數(shù)據(jù)發(fā)生變化時(shí)才發(fā)出通知。一旦接到通知,你就可以刷新你的緩沖區(qū)或者采取你需要的任何措施。
在SQL Server 2005中引入的一種新特征“Service Broker”使得查詢(xún)通知成為可能。Service Broker把隊(duì)列機(jī)制引入到數(shù)據(jù)庫(kù)管理中,它使用一組隊(duì)列與服務(wù)進(jìn)行通訊,而服務(wù)反過(guò)來(lái)也知道如何往回通訊以調(diào)用相應(yīng)的實(shí)體。其實(shí),這些隊(duì)列和服務(wù)都是一些與表、視圖和存儲(chǔ)過(guò)程一樣的類(lèi)對(duì)象。盡管完全可以在SQL Server內(nèi)使用Service Broker,但是ADO.NET知道如何與Service Broker進(jìn)行通訊以觸發(fā)這種機(jī)制并且從Service Broker中檢索回通知。
注意 當(dāng)SQL Server中的數(shù)據(jù)發(fā)生改變時(shí),查詢(xún)通知允許你緩沖數(shù)據(jù)并且通知你。
在.NET一端,存在很多種“鉤入”這種功能的方式。ADO.NET 2.0提供了System.Data.SqlClient.SqlDependency和System.Data.Sql.SqlNotificationRequest類(lèi)。SqlDependency是SqlNotificationRequest的一種高級(jí)實(shí)現(xiàn),并且是當(dāng)使用ADO.NET 2.0時(shí)你最有可能使用的類(lèi)。ASP.NET 2.0也通過(guò)System.Web.Caching.SqlCache-Dependency類(lèi)(它提供了一個(gè)針對(duì)SqlDependency的包裝器)與Service Broker進(jìn)行通訊,而且這是直接通過(guò)在一個(gè)ASP.NET頁(yè)面中使用<%OutputCache>指令以聲明方式提供的功能實(shí)現(xiàn)的。這允許ASP.NET開(kāi)發(fā)者容易地實(shí)現(xiàn)使依賴(lài)于SQL Server中的數(shù)據(jù)中的緩存無(wú)效。
二、.NET與Service Broker的通訊
上面這些技術(shù)是如何聯(lián)合到一起來(lái)解決“緩沖之謎”的呢?盡管你可以采取很多的措施以允許SQL Server把服務(wù)提供給.NET;但是,關(guān)鍵還在于,發(fā)送到SQL Server的查詢(xún)具有一個(gè)依附到它們的標(biāo)志以便告訴SQL Server,除了返回結(jié)果集外,SQL Server還應(yīng)該把該查詢(xún)(及其請(qǐng)求者)注冊(cè)到Service Broker。為此,你要?jiǎng)?chuàng)建一個(gè)感知該查詢(xún)的隊(duì)列和一個(gè)依附到該隊(duì)列的服務(wù),并且知道如何返回到客戶(hù)端。如果該結(jié)果集中的任何一行在數(shù)據(jù)庫(kù)中得到更新,那么在相關(guān)隊(duì)列中的項(xiàng)將觸發(fā),并且反過(guò)來(lái),把一條消息發(fā)送到它的服務(wù),然后把一個(gè)通知發(fā)送回初始化該請(qǐng)求的應(yīng)用程序。
圖1是SQL Server Management Studio的一個(gè)快照,它顯示了在數(shù)據(jù)庫(kù)的Service Broker部分中的隊(duì)列(Queues)和服務(wù)(Services)。
圖1.該圖顯示了.NET的查詢(xún)通知所使用的Pubs數(shù)據(jù)庫(kù)中的缺省隊(duì)列和服務(wù)。
下面是理解這一過(guò)程的一些有關(guān)重要內(nèi)容:
· 存在一些規(guī)則以指出SQL Server接收哪些類(lèi)型的查詢(xún)。
· 一旦SQL Server發(fā)送回通知,隊(duì)列和服務(wù)即被刪除。這意味著,你僅能在每次請(qǐng)求中得到一個(gè)通知。一個(gè)典型的應(yīng)用程序會(huì)重新查詢(xún)數(shù)據(jù)庫(kù)并且,在同時(shí),請(qǐng)求在Service Broker中創(chuàng)建一種新的依賴(lài)性。
· 返回到應(yīng)用程序的信息也不過(guò)是“something changed”。該應(yīng)用程序并不被通知改變了什么(請(qǐng)參考本文中的SQLNotificationEventArgs
節(jié)了解更多的信息)。
· 盡管依賴(lài)性被綁定到從查詢(xún)中返回的行上;但是,它并不被查詢(xún)中的單個(gè)列加以過(guò)濾。如果你有一個(gè)查詢(xún)—它返回你的組織的基本成員姓名以及那些單個(gè)改變之一的地址(但是,其姓名并不改變),這將觸發(fā)一個(gè)改變通知。很希望,這種特殊行為在未來(lái)的版本中會(huì)有所改變。
· 通知被返回,通過(guò)一個(gè)專(zhuān)門(mén)針對(duì)這一目的建立的SqlConnection。這個(gè)連接并不加入連接池中。
三、何時(shí)使用查詢(xún)通知
查詢(xún)通知是針對(duì)于并不經(jīng)常改變的數(shù)據(jù)而設(shè)計(jì)的。最好把它應(yīng)用于服務(wù)器端的應(yīng)用程序(例如ASP.NET或remoting)而不是客戶(hù)端應(yīng)用程序(例如Windows表單應(yīng)用程序)。記住,每一個(gè)通知請(qǐng)求都要在SQL Server中注冊(cè)。如果你擁有大量的都有通知請(qǐng)求的客戶(hù)端應(yīng)用程序,那么這可能會(huì)導(dǎo)致你的服務(wù)器產(chǎn)生資源問(wèn)題。微軟推薦,對(duì)于客戶(hù)端應(yīng)用程序,你應(yīng)該限制查詢(xún)通知使用為不多于十個(gè)并行用戶(hù)。
對(duì)于大規(guī)模應(yīng)用程序來(lái)說(shuō),查詢(xún)通知可能是一種強(qiáng)有力的幫助,而不用簡(jiǎn)單地添加越來(lái)越多的服務(wù)器以滿(mǎn)足要求。設(shè)想,有一家大型的為成千上百萬(wàn)用戶(hù)提供在線(xiàn)軟件更新服務(wù)的軟件公司。不是使每一個(gè)用戶(hù)的更新操作都觸發(fā)服務(wù)器上的另一個(gè)查詢(xún)來(lái)確定需要哪些組件,而是能夠緩沖查詢(xún)結(jié)果并且可以直接從該緩存中服務(wù)匹配的查詢(xún)。
注意:對(duì)于客戶(hù)端應(yīng)用程序來(lái)說(shuō),應(yīng)該限制你的查詢(xún)通知使用—不多于十個(gè)并發(fā)用戶(hù)。
對(duì)于較小規(guī)模的情況而言,下拉式列表框是另一種典型的數(shù)據(jù)集;此時(shí)該數(shù)據(jù)集更新的次數(shù)并不如請(qǐng)求的次數(shù)多。產(chǎn)品列表、州列表、國(guó)家列表、供應(yīng)商、銷(xiāo)售人,甚至更多不太需要頻繁改變的信息正是使用通知的較好候選。
四、為使用查詢(xún)通知作準(zhǔn)備
因?yàn)槟J(rèn)情況下SQL Server 2005處于高度安全的狀態(tài),所以你需要“打開(kāi)”一些功能才能使用查詢(xún)通知。首先,你要使用的每一個(gè)數(shù)據(jù)庫(kù)都需要啟動(dòng)Service Broker功能。為此,你可以在T-SQL中使用如下命令實(shí)現(xiàn):
USE mydatabase
ALTER DATABASE mydb SET ENABLE_BROKER
另外,你需要授予一些SQL Server權(quán)限以允許非管理員帳戶(hù)能夠參與使用查詢(xún)通知。
五、SqlDependency.Start和Stop
SqlDependency和SqlCacheDependency都要求,在任何通知請(qǐng)求前先調(diào)用靜態(tài)方法SqlDependency.Start()。這個(gè)方法負(fù)責(zé)創(chuàng)建一個(gè)SqlConnection以實(shí)現(xiàn)在數(shù)據(jù)改變時(shí)接收通知。注意,你僅需要在一個(gè)應(yīng)用程序的生命周期的開(kāi)始建立這些內(nèi)容。例如,在一個(gè)ASP.NET應(yīng)用程序中,global.asax文件的Application_Start事件處理器就是實(shí)現(xiàn)這一功能的好地方。
注意,對(duì)包含在通知中的每一個(gè)連接都應(yīng)該調(diào)用Start方法。因此,如果你在應(yīng)用程序中存取多個(gè)數(shù)據(jù)庫(kù),那么你需要為每一個(gè)數(shù)據(jù)庫(kù)調(diào)用Start。在下列示例中,有一個(gè)針對(duì)Pubs數(shù)據(jù)庫(kù)的連接串pubsConn,它在這個(gè)應(yīng)用程序的web.config文件中定義。
為了切斷這個(gè)連接,你可以使用SqlDependency.Stop(),這也是一個(gè)靜態(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的同時(shí)觀察SQL Server Profiler,那么你會(huì)看到許多有趣的信息。當(dāng)調(diào)用Start時(shí),應(yīng)用程序運(yùn)行一個(gè)查詢(xún)以確保支持Service Broker,然后創(chuàng)建一個(gè)存儲(chǔ)過(guò)程備以后用于清除在Service Broker基礎(chǔ)結(jié)構(gòu)中的SqlDependency隊(duì)列和服務(wù)。最后,它運(yùn)行一個(gè)SQL Server 2005 WaitFor命令,該命令負(fù)責(zé)查詢(xún)?cè)贜otification Service部分的入口。這就是如果你使用ADO.NET的低級(jí)SqlNotificationRequest對(duì)象的話(huà)所有你需要顯式完成的事情。
在整個(gè)的.NET 2.0的設(shè)計(jì)過(guò)程中,SqlDependency底層架構(gòu)從一種推模式(來(lái)自SQL Server)改變?yōu)橐环N拉模式(來(lái)自.NET)。這樣做的原因是為了解決第一次設(shè)計(jì)時(shí)所導(dǎo)致的一些安全問(wèn)題。微軟的Sushil Chordia在MSDN上發(fā)表了一篇有關(guān)于這種改進(jìn)的文章,該文詳細(xì)描述了這一改進(jìn)的內(nèi)在機(jī)理。
六、你的第一個(gè)通知
下面,讓我們開(kāi)始使用SqlDependency來(lái)分析一下所有上面這些是如何協(xié)同工作的。
首先,我們創(chuàng)建一個(gè)類(lèi)NotificationTest來(lái)存取你的數(shù)據(jù)。在這個(gè)類(lèi)中,還要?jiǎng)?chuàng)建一個(gè)典型的函數(shù)以便從Pubs數(shù)據(jù)庫(kù)的Authors表中查詢(xún)一些數(shù)據(jù)并返回一個(gè)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)在,讓我們修改代碼來(lái)加入這種依賴(lài)性。首先,聲明一個(gè)名為SqlDependency的對(duì)象。為了使之用于該類(lèi)中的其它函數(shù)中,我把它定義為一個(gè)類(lèi)變量。
然后,你需要改變這個(gè)查詢(xún)。查詢(xún)通知要求你顯式地列舉在你的查詢(xún)中的列,以及總是使用一種“兩部分”的表名。注意一下在修改后的代碼示例中的新的查詢(xún)文本。
然后,實(shí)例化新的SqlDependency并且把它依附到命令中。
就是這些。當(dāng)執(zhí)行命令時(shí),依賴(lài)性隨著它直到數(shù)據(jù)庫(kù)。在它處理查詢(xún)的同時(shí),SQL Server能夠看到這一依賴(lài)性并且把它發(fā)送到Service Broker以注冊(cè)它。
以下為引用的內(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)注冊(cè)了依賴(lài)性,但是當(dāng)通知返回到應(yīng)用程序時(shí)你還根本沒(méi)有捕獲它。不過(guò),SqlDependency類(lèi)提供了兩種方式來(lái)了解一個(gè)通知。一種方式是通過(guò)OnChange事件,你可以通過(guò)創(chuàng)建一個(gè)代理來(lái)捕獲它;另一種方式是通過(guò)屬性HasChanges,你可以在你的應(yīng)用程序邏輯中對(duì)之進(jìn)行測(cè)試。在下列代碼中,我在OnDepChange事件中添加了代碼以便在后面的某個(gè)時(shí)候測(cè)試通知。
以下為引用的內(nèi)容: Imports System.Data.SqlClient |
現(xiàn)在,我們來(lái)看一下其工作原理。首先,把一個(gè)斷點(diǎn)放到OnDepChange事件的End Sub代碼行。然后,從你喜歡的網(wǎng)頁(yè)、表單程序或控制臺(tái)程序中調(diào)用DepTest函數(shù)來(lái)進(jìn)行測(cè)試。在返回SqlDataReader后,在Visual Studio 2005的Server Explorer或在SQL Server Management Studio中打開(kāi)Authors表并且編輯某一個(gè)字段內(nèi)容。例如,一旦鎖定這一改變,那么,當(dāng)你把光標(biāo)移動(dòng)到表中的一個(gè)新行時(shí),斷點(diǎn)應(yīng)該被激活。
七、SQLNotificationEventArgs
當(dāng)你看到通知的確從數(shù)據(jù)庫(kù)中傳來(lái)時(shí),你可以分析一下相應(yīng)變量的值,它是一個(gè)SqlNotificationEventArgs對(duì)象。SqlDependency總是隨著OnChange事件返回這個(gè)對(duì)象,而且它是很有用的。其中,SqlNotificationInfo是一個(gè)具有18種可能值的枚舉類(lèi)型。其中,一些值對(duì)應(yīng)情況正常,而另一些顯示出了問(wèn)題。這些枚舉中有Update,Insert和Delete—告訴你在數(shù)據(jù)中發(fā)生了什么類(lèi)型的變化。還有其它一些值即使在事件發(fā)生時(shí)也不會(huì)被發(fā)送。例如,重新啟動(dòng)服務(wù)器將激發(fā)所有的通知;而枚舉值Drop或Truncate告訴你已經(jīng)對(duì)依賴(lài)的表實(shí)現(xiàn)了某種操作。
另外,還存在一些依賴(lài)性甚至還不能被注冊(cè)的情形,例如如果你試圖對(duì)一個(gè)UPDATE查詢(xún)?cè)O(shè)置一個(gè)依賴(lài)性將返回Invalid。而返回值Query顯示你的查詢(xún)語(yǔ)法并不符合通知的嚴(yán)格規(guī)則。上面枚舉表中的最后兩個(gè)枚舉值,還有其它幾個(gè)與不能注冊(cè)查詢(xún)相關(guān)的枚舉值在執(zhí)行該命令時(shí)被立即返回。
通過(guò)查找MSDN庫(kù)中的有關(guān)SqlNotificationInfo枚舉文檔,你可以得到這些枚舉的完全列表。
當(dāng)我一些場(chǎng)合上談?wù)摬樵?xún)通知時(shí),人們總是問(wèn)我:“通知是否會(huì)告訴你發(fā)生了什么事情?”;卮鹗“不會(huì)”。
總之,SQLNotificationEventArgs能夠向你給出一個(gè)通知中最為詳細(xì)的信息,而這些信息在調(diào)試排錯(cuò)時(shí)是非常有用的。
分享:SQL2005數(shù)據(jù)庫(kù)轉(zhuǎn)到SQL2000的步驟1. 生成for2000版本的數(shù)據(jù)庫(kù)腳本 2005的manger studio -- 打開(kāi)"對(duì)象資源管理器"(沒(méi)有的話(huà)按F8), 連接到你的實(shí)例 -- 右鍵要轉(zhuǎn)到2000的庫(kù) -- 任務(wù) -- 生成腳本 -- 在
- sql 語(yǔ)句練習(xí)與答案
- 深入C++ string.find()函數(shù)的用法總結(jié)
- SQL Server中刪除重復(fù)數(shù)據(jù)的幾個(gè)方法
- sql刪除重復(fù)數(shù)據(jù)的詳細(xì)方法
- SQL SERVER 2000安裝教程圖文詳解
- 使用sql server management studio 2008 無(wú)法查看數(shù)據(jù)庫(kù),提示 無(wú)法為該請(qǐng)求檢索數(shù)據(jù) 錯(cuò)誤916解決方法
- SQLServer日志清空語(yǔ)句(sql2000,sql2005,sql2008)
- Sql Server 2008完全卸載方法(其他版本類(lèi)似)
- sql server 2008 不允許保存更改,您所做的更改要求刪除并重新創(chuàng)建以下表
- SQL Server 2008 清空刪除日志文件(瞬間日志變幾M)
- Win7系統(tǒng)安裝MySQL5.5.21圖解教程
- 將DataTable作為存儲(chǔ)過(guò)程參數(shù)的用法實(shí)例詳解
Mssql數(shù)據(jù)庫(kù)教程Rss訂閱編程教程搜索
Mssql數(shù)據(jù)庫(kù)教程推薦
- sql server多行數(shù)據(jù)拼接的實(shí)例方法
- sql where 1=1的優(yōu)缺點(diǎn)分析
- 黑客經(jīng)驗(yàn)談 MSSQL SA權(quán)限入侵的感悟
- 如何將SQL2000數(shù)據(jù)庫(kù)升級(jí)到SQL2005
- 在SQL Server中通過(guò).NET遠(yuǎn)程的執(zhí)行SQL文件
- 淺談自定義數(shù)據(jù)庫(kù)自動(dòng)編號(hào)初始值和步進(jìn)值
- 如何在SQL 2005中實(shí)現(xiàn)循環(huán)每一行做一定的操作
- SQL Server 2005中更改sa的用戶(hù)名的方法
- 如何使用SQL Server數(shù)據(jù)庫(kù)中查詢(xún)累計(jì)值
- 淺談SQL Server元數(shù)據(jù)的管理與應(yīng)用
猜你也喜歡看這些
- SQL提示Login failed for user#039;sa#039;錯(cuò)誤的解決方案
- mysql5.6.10安裝詳細(xì)圖文教程
- 深入探討:MySQL數(shù)據(jù)庫(kù)MyISAM與InnoDB存儲(chǔ)引擎的比較
- mysql的binlog太大太多占用大量磁盤(pán)的解決
- Mysql DNS反向解析導(dǎo)致連接超時(shí)過(guò)程分析(skip-name-resolve)
- Mysql中文亂碼以及導(dǎo)出為sql語(yǔ)句和Excel問(wèn)題解決方法[圖文]
- mysql隨機(jī)查詢(xún)的優(yōu)化
- 從mysql中導(dǎo)出單個(gè)表結(jié)構(gòu)和數(shù)據(jù)
- 基于一致性hash算法(consistent hashing)的使用詳解
- MySQL如何設(shè)置密碼
- 相關(guān)鏈接:
- 教程說(shuō)明:
Mssql數(shù)據(jù)庫(kù)教程-剖析SQL Server 2005查詢(xún)通知之基礎(chǔ)篇。