本文給出了類型化和非類型化xml列各自的優(yōu)勢(shì)、將sql server 2000數(shù)據(jù)庫(kù)遷移到sql server2005,新的異常處理如何工作;如果表的架構(gòu)發(fā)生更改,我如何執(zhí)行操作等,供大家參考!
sql server 2005 包括對(duì)transact-sql (t-sql) 語言的幾項(xiàng)重要改進(jìn)。新增功能之一是一種新的觸發(fā)器,它在數(shù)據(jù)定義語言 (ddl) 語句運(yùn)行時(shí)激發(fā)。在跟蹤或保護(hù)數(shù)據(jù)庫(kù)對(duì)象的創(chuàng)建和修改,或?qū)?shù)據(jù)庫(kù)服務(wù)器進(jìn)行更改時(shí),ddl 觸發(fā)器非常有用。另一個(gè)新功能涉及異常處理,該功能因包含try/catch 塊而在異常處理方面向前飛躍了一大步。另一組新功能則以新的xml數(shù)據(jù)類型為中心,該數(shù)據(jù)類型在與sql server交互的企業(yè)應(yīng)用程序中管理xml數(shù)據(jù)方面前進(jìn)了一大部?,F(xiàn)在,xml 文檔或片段可以存儲(chǔ)于 xml 列、綁定到架構(gòu)、還可以利用 xquery 語法查詢。本文匯總各類問題來做出詳細(xì)解答。
問:類型化和非類型化 xml 列各自的優(yōu)勢(shì)是什么?
答:非類型化 xml 列可以存儲(chǔ)所有格式規(guī)范的 xml 片段或文檔,而類型化 xml 列可以綁定到 xml 架構(gòu)。如果不確定 xml 將遵循哪個(gè)架構(gòu),則非類型化 xml 很有用。例如,如果您必須使用另一個(gè)應(yīng)用程序的某些 xml,但無法確定數(shù)據(jù)將遵循哪個(gè) xml 架構(gòu),則可以使用非類型化 xml 列來執(zhí)行這項(xiàng)工作。當(dāng)然,非類型化 xml 也會(huì)帶來其他問題。例如,不能針對(duì)某個(gè)架構(gòu)編程,因此很難有效地使用 xml。但有時(shí)無法避免非類型化 xml。創(chuàng)建非類型化 xml 列非常簡(jiǎn)單,如下所示:
create table foo(fooid int, somexml xml)架構(gòu)不綁定到 xml 列的另一個(gè)結(jié)果是,sql server® 2005 會(huì)將非類型化 xml 作為一個(gè)字符串存儲(chǔ)。這是件好事還是壞事?實(shí)際上,既是好事也是壞事。將 xml 作為字符串存儲(chǔ)使您可以更靈活地存儲(chǔ)任何 xml 片段或文檔。根據(jù)應(yīng)用程序的業(yè)務(wù)規(guī)則,您可能需要這種方式。另一方面,將 xml 作為字符串存儲(chǔ)意味著,與類型化 xml 相比,既不能有效地存儲(chǔ)也不能有效地搜索 xml 數(shù)據(jù)。并且既不會(huì)告訴 sql server xml 將包含哪些內(nèi)容,也不會(huì)告訴它層次結(jié)構(gòu)和 xml 節(jié)點(diǎn)的數(shù)據(jù)類型。但請(qǐng)記住,僅僅因?yàn)檫@些是非類型化 xml 列并不意味著它們可以接受您設(shè)計(jì)出的任何格式。類型化和非類型化 xml 列仍然只接受格式規(guī)范的 xml。
|||如果您要存儲(chǔ)架構(gòu)已知的 xml 文檔,類型化 xml 列很理想。架構(gòu)可以定義元素、屬性、它們的數(shù)據(jù)類型、需要哪些字段以及數(shù)據(jù)的整個(gè)層次結(jié)構(gòu)。由于這種詳細(xì)信息有關(guān) xml 列的數(shù)據(jù),因此 sql server 2005 可以在內(nèi)部更加有效地存儲(chǔ) xml 數(shù)據(jù)。如果您嘗試存儲(chǔ)與架構(gòu)不匹配的 xml 數(shù)據(jù),則 sql server 會(huì)檢測(cè)到這一點(diǎn)并阻止您。
創(chuàng)建類型化 xml 列就像在括號(hào)中添加架構(gòu)名稱一樣簡(jiǎn)單,如下所示:
create table foo(fooid int, somexml xml(content fooschema))該語句指出 somexml 列必須遵循名為 fooschema 的 xml 架構(gòu)集合。通過分別包含相應(yīng)的關(guān)鍵字 document 或 content,xml 可指定為必須是一個(gè)文檔或者可以包含一個(gè)片段。如果省略,則默認(rèn)值為 content。
可以使用 t-sql 命令將 xml 架構(gòu)集合添加到數(shù)據(jù)庫(kù)中,如下所示:
create xml schema collection [fooschema] as n 'put your schema here'也可以使用 sql server management studio (ssms) 創(chuàng)建 xml 架構(gòu)集合模板。從 view 菜單打開 template explorer,然后導(dǎo)航到 xml schema collections 節(jié)點(diǎn)并展開它。然后,您可以雙擊 create 模板打開一個(gè)模板,該模板為您創(chuàng)建 xml 架構(gòu)集合提供了一個(gè)良好的語法開端(參見圖 1)。

圖1:xml架構(gòu)集合模板是ssms
sql server 2005 隨附的 adventureworks 數(shù)據(jù)庫(kù)有一個(gè)名為 humanresources.jobcandidate 的表。該表包含一個(gè)名為 resume 的列,該列是一個(gè)綁定到架構(gòu)集合 humanresources.hrresumeschemacollection 的 xml 列。該列中存儲(chǔ)的所有 xml 數(shù)據(jù)都必須遵循該架構(gòu)。

圖2:resume架構(gòu)
類型化和非類型化 xml 列都可以進(jìn)行索引,但索引時(shí),綁定到架構(gòu)的 xml 列比非類型化 xml 列具有更多優(yōu)點(diǎn)。將 xml 索引應(yīng)用于非類型化 xml 列時(shí),必須分析大部分 xml 結(jié)構(gòu)來定位匹配的節(jié)點(diǎn)。但是,將 xml 索引應(yīng)用于類型化 xml 列時(shí),特定節(jié)點(diǎn)是可識(shí)別的并可根據(jù)架構(gòu)定位。因此,索引可以在類型化 xml 中更有效地工作,因?yàn)樗涝谀睦锊檎?。此外,如果需要搜索一個(gè)數(shù)值范圍,則索引將用非類型化 xml 執(zhí)行一個(gè)數(shù)據(jù)類型轉(zhuǎn)換(因?yàn)閿?shù)據(jù)類型是未知的)。類型化 xml 定義自己的數(shù)據(jù)類型,從而避免了轉(zhuǎn)換開銷。
問:我剛剛將 sql server 2000 數(shù)據(jù)庫(kù)遷移到 sql server 2005。我聽說 sql server 2005 在 t-sql 中引入了 try/catch 異常處理。與現(xiàn)有的 if @@error <> 0 技術(shù)相比,新的異常處理如何工作呢?
答:通常對(duì)使用 t-sql 編寫代碼的抱怨是,t-sql 始終缺少一個(gè)健壯的異常處理結(jié)構(gòu)。通過 sql server 2000,您可以編寫 t-sql 批處理代碼,以檢查是否存在錯(cuò)誤甚至何時(shí)引發(fā)錯(cuò)誤(如果需要)。但與 try/catch 技術(shù)相比,執(zhí)行此操作的技術(shù)是最基本的。首先,我將使用 @@error 函數(shù)定義與異常處理相關(guān)聯(lián)的問題,然后展示新的 try/catch 技術(shù)與之相比是如何執(zhí)行的。
sql server 公開內(nèi)置的 @@error 函數(shù),該函數(shù)返回所執(zhí)行的上一條 t-sql 命令的錯(cuò)誤號(hào)。該函數(shù)的問題在于,它始終返回從剛剛執(zhí)行的上一個(gè)語句返回的錯(cuò)誤。這意味著,如果您執(zhí)行一個(gè)導(dǎo)致錯(cuò)誤的 insert 語句,然后執(zhí)行另一個(gè)不會(huì)導(dǎo)致錯(cuò)誤的任意 sql 語句,之后再查看 @@error 的返回值,則該函數(shù)將返回 0,原因是上一個(gè)語句沒有返回錯(cuò)誤。您必須十分小心,以確保在執(zhí)行每個(gè)單獨(dú)語句之后檢查 @@error 的值。
begin transaction
delete [order details] where orderid in
(select orderid from orders where customerid = 'alfki')
if @@error <> 0
begin
rollback transaction
return
end
delete orders where customerid = 'alfki'
if @@error <> 0
begin
rollback transaction
return
end
delete customers where customerid = 'alfki'
if @@error <> 0
begin
rollback transaction
return
end
print 'i got here'
-- normally do a commit transaction here.
-- but i do a rollback so i don't truly delete my test data.
rollback transaction展示一些示例代碼,這些代碼將在事務(wù)內(nèi)部運(yùn)行,依次刪除客戶的定單詳情、定單以及客戶本身。在每個(gè) delete 語句之后,代碼都會(huì)檢查 @@error 函數(shù)的值,以查看 delete 語句是否導(dǎo)致了錯(cuò)誤。如果是,則回滾事務(wù),停止執(zhí)行代碼,然后從批處理操作返回。
這是標(biāo)準(zhǔn)的事務(wù)管理,即如果發(fā)生錯(cuò)誤,則中止事務(wù),然后將數(shù)據(jù)的狀態(tài)返回至其初始狀態(tài)。請(qǐng)注意,如果一切順利并且沒有發(fā)生錯(cuò)誤,我會(huì)打印一個(gè)成功消息,然后回滾事務(wù)。通常,我不會(huì)成功地進(jìn)行回滾,因?yàn)檫@是一個(gè)測(cè)試事務(wù),我實(shí)際上并不希望刪除我的數(shù)據(jù)。
請(qǐng)注意,我必須遵循帶有 @@error 函數(shù)的每個(gè)語句,然后再使用 rollback 和 return。該方法十分糟糕。假設(shè)編寫一個(gè)包含許多查詢(這些查詢都需要檢查)的事務(wù)。該過程可以通過 goto 語句來稍加簡(jiǎn)化,當(dāng)然我并不是 goto 語句的提倡者,因?yàn)樗鼈円琅f未解決需要在查詢操作之后立即檢查 @@error 函數(shù)的問題。
sql server 2005 仍然支持 @@error 函數(shù),但它還包括了廣為人知的 try/catch 模式。try/catch 結(jié)構(gòu)與 c# try/catch 結(jié)構(gòu)的類似之處在于,在 try 塊中捕獲錯(cuò)誤,然后轉(zhuǎn)移到 catch 塊執(zhí)行。(t-sql 版本的 try/catch 沒有 finally 子句選項(xiàng),但 c# 版本有。您可以通過捕獲異常、不執(zhí)行返回、然后使用適當(dāng)?shù)那宄a執(zhí)行 catch 塊來進(jìn)行模擬。)因此,在某些情況下需要注意這一點(diǎn),例如,在指定了 cursor 并在 t-sql try 塊中引發(fā)錯(cuò)誤時(shí)打開該游標(biāo)的情況。在這種情況下,應(yīng)該在 catch 塊中檢查游標(biāo)以查看它是否已打開;如果已打開,則應(yīng)將其關(guān)閉并取消指定。
begin try
begin transaction
delete [order details] where orderid in
(select orderid from orders where customerid = 'alfki')
delete orders where customerid = 'alfki'
delete customers where customerid = 'alfki'
print 'committing deletes'
commit transaction
end try
begin catch
rollback transaction
return
end catch看到上面代碼中的 try/catch 結(jié)構(gòu)后,您可能會(huì)震驚于它與 @@error 技術(shù)相比是多么簡(jiǎn)潔。請(qǐng)注意,對(duì)于 try/catch 塊,不需要重復(fù)檢查是否有錯(cuò)誤,因而減少了代碼行數(shù)同時(shí)也減少了出現(xiàn)編碼錯(cuò)誤的地方。
上面代碼中的代碼試圖開始一個(gè)事務(wù),執(zhí)行一系列 delete 語句,然后提交該事務(wù)。(另請(qǐng)注意,在我的示例中,我沒有提交事務(wù)而是回滾該事務(wù),因此實(shí)際上并沒有刪除數(shù)據(jù)。實(shí)際上,這應(yīng)該是一個(gè) commit tran 語句。)
可以在 try/catch 結(jié)構(gòu)中訪問多個(gè)內(nèi)置函數(shù),以幫助您確定導(dǎo)致代碼進(jìn)入 catch 塊的原因。例如,可以在 catch 塊內(nèi)部添加以下語句,返回有關(guān)該錯(cuò)誤的信息:
select
error_line() as errorline,
error_message() as errormessage,
error_number() as errornumber,
error_procedure() as errorprocedure,
error_severity() as errorseverity,
error_state() as errorstate這些函數(shù)(如果適用)將返回發(fā)生錯(cuò)誤的行號(hào)、錯(cuò)誤消息、錯(cuò)誤號(hào)、存儲(chǔ)過程或發(fā)生錯(cuò)誤的觸發(fā)器、錯(cuò)誤的嚴(yán)重級(jí)別以及錯(cuò)誤的狀態(tài)級(jí)別。
try/catch 結(jié)構(gòu)捕獲嚴(yán)重度為 11 到 19(包括 11 和 19)的錯(cuò)誤。低于 11 的嚴(yán)重級(jí)別是警告,不視為錯(cuò)誤。嚴(yán)重級(jí)別為 20 及以上的錯(cuò)誤視為嚴(yán)重錯(cuò)誤。然而,如果這些嚴(yán)重級(jí)別為 20 及以上的錯(cuò)誤沒有導(dǎo)致數(shù)據(jù)庫(kù)引擎停止,則它們將由 try/catch 捕獲??傊?,try/catch 語句更易于讀取、更易于維護(hù),且更不容易導(dǎo)致復(fù)制和粘貼錯(cuò)誤。此外,@@error 技術(shù)也不總是很可靠。例如,某些錯(cuò)誤會(huì)中止計(jì)劃或整個(gè)批處理。
問:我知道可以創(chuàng)建觸發(fā)器來審核對(duì)數(shù)據(jù)的更改,但是如果表的架構(gòu)發(fā)生更改,我如何執(zhí)行操作呢?
答:我在簡(jiǎn)介中提到過,現(xiàn)在有了一個(gè)新的觸發(fā)器:sql server 2005 中的 ddl 觸發(fā)器。數(shù)據(jù)操作語言 (dml) 觸發(fā)器基于數(shù)據(jù)操作激發(fā),而 ddl 觸發(fā)器在對(duì)數(shù)據(jù)庫(kù)架構(gòu)或服務(wù)器進(jìn)行更改時(shí)激發(fā)。創(chuàng)建的 ddl 觸發(fā)器只能在發(fā)生觸發(fā)事件之后激發(fā),而 dml 觸發(fā)器則不同,它可以在事件之后或代替事件激發(fā)。以下是創(chuàng)建 ddl 觸發(fā)器的語法,在 sql server 2005 文檔中進(jìn)行了概述:
create trigger trigger_name
on { all server | database }
[ with encryption ]
{ for | after } { event_type [ ,...n ] | ddl_database_level_events }
[ with append ]
[ not for replication ]
{ as
{ sql_statement [ ...n ] | external name < method specifier > }
}
< method_specifier > ::= assembly_name:class_name[::method_name] 請(qǐng)注意,您可以創(chuàng)建觸發(fā)器,以便它在對(duì)數(shù)據(jù)庫(kù)的架構(gòu)或數(shù)據(jù)庫(kù)服務(wù)器進(jìn)行更改時(shí)激發(fā)。您還可以通過指定事件類型(這些類型都列在 sql server 2005 文檔中)來定義導(dǎo)致觸發(fā)器激發(fā)的事件?;蛘撸部梢酝ㄟ^指定 ddl_database_level_events 標(biāo)識(shí)符讓 ddl 觸發(fā)器在所有事件之后激發(fā)。
通過 ddl 觸發(fā)器,您可以記錄對(duì)數(shù)據(jù)庫(kù)的架構(gòu)所作的更改??梢允褂?ddl 觸發(fā)器審核更改,而不是防止更改。或者,也可以通過 ddl 觸發(fā)器記錄嘗試操作,然后將其回滾。您可能還希望在創(chuàng)建對(duì)象時(shí)對(duì)其強(qiáng)制命名約定。例如,您可能希望所有存儲(chǔ)過程都以 pr 為前綴。通過 ddl 觸發(fā)器,您可以強(qiáng)制該命名約定。
ddl 觸發(fā)器與 dml 觸發(fā)器的類似之處在于,它們都可以回滾事務(wù)。然而,ddl 觸發(fā)器沒有插入或刪除的表。ddl 觸發(fā)器能夠訪問一個(gè)名為 eventdata 的內(nèi)置函數(shù),該函數(shù)在 xml 數(shù)據(jù)類型中返回 xml(包含有關(guān)激發(fā)觸發(fā)器的事件的信息)。每個(gè)事件在事件數(shù)據(jù)中顯示的信息都略有不同。但是,eventdata 函數(shù)始終為所有事件返回以下信息:
◆事件的時(shí)間
◆事件的類型
◆導(dǎo)致觸發(fā)器激發(fā)的連接 spid
◆發(fā)生事件的用戶上下文的登錄名和用戶名
create trigger ddltrigger_procnamingconvention
on database
after create_procedure, alter_procedure
as
declare @eventdataxml xml
set @eventdataxml = eventdata()
if substring(@eventdataxml.value('(//objectname)[1]',
'varchar(200)'), 1, 2) = 'pr'
print 'starts with pr'
else
begin
print 'does not start with pr'
rollback transaction
end
go 最大的網(wǎng)站源碼資源下載站,
|||請(qǐng)注意,這段代碼中的 ddl 觸發(fā)器定義為,在當(dāng)前數(shù)據(jù)庫(kù)上創(chuàng)建或更改存儲(chǔ)過程時(shí)激發(fā)。當(dāng)觸發(fā)器激發(fā)后,事件的數(shù)據(jù)會(huì)被捕獲并存儲(chǔ)在本地 xml 變量中。盡管這不是必要的,但如果您打算多次訪問 eventdata 函數(shù),這有助于使觸發(fā)器更高效。然后,觸發(fā)器會(huì)檢查對(duì)象的名稱是否以 pr 開頭。如果是,則允許事務(wù)完成;如果不是,則回滾事務(wù),并且存儲(chǔ)過程將保持不變。在本例中,我知道 objectname 元素將包含存儲(chǔ)過程的名稱,因?yàn)閮H在創(chuàng)建或更改存儲(chǔ)過程時(shí)才會(huì)調(diào)用觸發(fā)器。
<event_instance>
<eventtype>create_procedure</eventtype>
<posttime>2005-10-20t00:52:16.160</posttime>
<spid>51</spid>
<servername>mydbserver</servername>
<loginname>camelotjpapa</loginname>
<username>dbo</username>
<databasename>adventureworks</databasename>
<schemaname>dbo</schemaname>
<objectname>test1</objectname>
<objecttype>procedure</objecttype>
<tsqlcommand>
<setoptions ansi_nulls="on" ansi_null_default="on" ansi_padding="on"
quoted_identifier="on" encrypted="false" />
<commandtext>create proc test1 as select getdate()</commandtext>
</tsqlcommand>
</event_instance>顯示執(zhí)行以下命令后該觸發(fā)器的事件數(shù)據(jù):
create proc test1 as select getdate您還可以捕獲事件數(shù)據(jù),并將其完整存儲(chǔ)到審核表的 xml 列中。另一個(gè)選擇是抽出特定節(jié)點(diǎn)的內(nèi)容,并將其單獨(dú)存儲(chǔ)。顯然,實(shí)現(xiàn)視具體情況而定,但 ddl 觸發(fā)器為您提供的選擇有很多。使用 ddl 觸發(fā)器時(shí)需要記住的一件事是,它們是同步操作的。由于是同步執(zhí)行,觸發(fā)器應(yīng)該盡可能不執(zhí)行費(fèi)時(shí)的操作。否則,它們會(huì)對(duì)數(shù)據(jù)庫(kù)服務(wù)器的性能造成負(fù)面影響。與 dml 觸發(fā)器一樣,應(yīng)該將 ddl 觸發(fā)器定義為僅執(zhí)行所需的操作并快速完成。如果需要異步執(zhí)行,可以使用 service broker 和 event notification 模型。
| 
 
 | 
新聞熱點(diǎn)
疑難解答
圖片精選