SQL Server 事務、異常和遊標

來源:互聯網
上載者:User

標籤:des   style   blog   http   使用   os   io   strong   

建議先閱讀預存程序:SQL Server 預存程序

Ø 事務

在資料庫中有時候需要把多個步驟的指令當作一個整體來運行,這個整體要麼全部成功,要麼全部失敗,這就需要用到事務。

    1、 事務的特點

        事務有若干條T-SQL指令組成,並且所有的指令昨晚一個整體提交給資料庫系統,執行時,這組指令要麼全部執行完成,要麼全部取消。因此,事務是一個不可分割的邏輯單元。

 

        事務有4個屬性:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)以及持久性(Durability),也稱作事務的ACID屬性。

        原子性:事務內的所有工作要麼全部完成,要麼全部不完成,不存在只有一部分完成的情況。

        一致性:事務內的然後操作都不能違反資料庫的然後約束或規則,事務完成時有內部資料結構都必須是正確的。

        隔離性:事務直接是相互隔離的,如果有兩個事務對同一個資料庫進行操作,比如讀取表資料。任何一個事務看到的所有內容要麼是其他事務完成之前的狀態,要麼是其他事務完成之後的狀態。一個事務不可能遇到另一個事務的中間狀態。

        持久性:事務完成之後,它對資料庫系統的影響是持久的,即使是系統錯誤,重新啟動系統後,該事務的結果依然存在。

 

    2、 事務的模式

        a、 顯示事務

        顯示事務就是使用者使用T-SQL明確的定義事務的開始(begin transaction)和提交(commit transaction)或復原事務(rollback transaction)

        b、 自動認可事務

        自動認可事務是一種能夠自動執行並能自動復原事務,這種方式是T-SQL的預設事務方式。例如在刪除一個表記錄的時候,如果這條記錄有主外鍵關係的時候,刪除就會受主外鍵約束的影響,那麼這個刪除就會取消。

        可以設定事務進入隱式方式:set implicit_transaction on;

        c、 隱含交易

        隱含交易是指當事務提交或復原後,SQL Server自動開始事務。因此,隱含交易不需要使用begin transaction顯示開始,只需直接失業提交事務或復原事務的T-SQL語句即可。

        使用時,需要設定set implicit_transaction on語句,將隱含交易模式開啟,下一個語句會啟動一個新的事物,再下一個語句又將啟動一個新事務。

 

    3、 交易處理

        常用T-SQL事務語句:

        a、 begin transaction語句

        開始事務,而@@trancount全域變數用來記錄事務的數目值加1,可以用@@error全域變數記錄執行過程中的錯誤資訊,如果沒有錯誤可以直接提交事務,有錯誤可以復原。

        b、 commit transaction語句

        復原事務,表示一個隱式或顯示的事務的結束,對資料庫所做的修改正式生效。並將@@trancount的值減1;

        c、 rollback transaction語句

        復原事務,執行rollback tran語句後,資料會復原到begin tran的時候的狀態

 

    4、 事務的樣本

--開始事務
begin transaction tran_bank;
declare @tran_error int;
set @tran_error = 0;
begin try
update bank set totalMoney = totalMoney - 10000 where userName = ‘jack‘;
set @tran_error = @tran_error + @@error;
update bank set totalMoney = totalMoney + 10000 where userName = ‘jason‘;
set @tran_error = @tran_error + @@error;
end try
begin catch
print ‘出現異常,錯誤編號:‘ + convert(varchar, error_number()) + ‘, 錯誤訊息:‘ + error_message();
set @tran_error = @tran_error + 1;
end catch
if (@tran_error > 0)
begin
--執行出錯,復原事務
rollback tran;
print ‘轉賬失敗,取消交易‘;
end
else
begin
--沒有異常,提交事務
commit tran;
print ‘轉賬成功‘;
end
go
 

Ø 異常

     在程式中,有時候完成一些Transact-SQL會出現錯誤、異常資訊。如果我們想自己處理這些異常資訊的話,需要手動捕捉這些資訊。那麼我們可以利用try catch完成。

TRY…CATCH 構造包括兩部分:一個 TRY 塊和一個 CATCH 塊。如果在 TRY 塊中所包含的 Transact-SQL 陳述式中檢測到錯誤條件,控制將被傳遞到 CATCH 塊(可在此塊中處理該錯誤)。

     CATCH 塊處理該異常錯誤後,控制將被傳遞到 END CATCH 語句後面的第一個 Transact-SQL 陳述式。如果 END CATCH 語句是預存程序或觸發器中的最後一條語句,控制將返回到調用該預存程序或觸發器的代碼。將不執行 TRY 塊中建置錯誤的語句後面的 Transact-SQL 陳述式。

     如果 TRY 塊中沒有錯誤,控制將傳遞到關聯的 END CATCH 語句後緊跟的語句。如果 END CATCH 語句是預存程序或觸發器中的最後一條語句,控制將傳遞到調用該預存程序或觸發器的語句。

     TRY 塊以 BEGIN TRY 語句開頭,以 END TRY 語句結尾。在 BEGIN TRY 和 END TRY 語句之間可以指定一個或多個 Transact-SQL 陳述式。CATCH 塊必須緊跟 TRY 塊。CATCH 塊以 BEGIN CATCH 語句開頭,以 END CATCH 語句結尾。在 Transact-SQL 中,每個 TRY 塊僅與一個 CATCH 塊相關聯。

     # 錯誤函數

TRY...CATCH 使用錯誤函數來捕獲錯誤資訊。
ERROR_NUMBER() 返回錯誤號碼。
ERROR_MESSAGE() 返回錯誤訊息的完整文本。此文本包括為任何可替換參數(如長度、對象名稱或時間)提供的值。
ERROR_SEVERITY() 返回錯誤嚴重性。
ERROR_STATE() 返回錯誤狀態數量。
ERROR_LINE() 返回導致錯誤的常式中的行號。
ERROR_PROCEDURE() 返回出現錯誤的預存程序或觸發器的名稱。
 

     樣本

--錯誤訊息預存程序
if (object_id(‘proc_error_info‘) is not null)
drop procedure proc_error_info
go
create proc proc_error_info
as
select
error_number() ‘錯誤編號‘,
error_message() ‘錯誤訊息‘,
error_severity() ‘嚴重性‘,
error_state() ‘狀態好‘,
error_line() ‘錯誤行號‘,
error_procedure() ‘錯誤對象(預存程序或觸發器)名稱‘;
go

 

     # 樣本:用異常處理錯誤資訊

--簡單try catch樣本
begin try
select 1 / 0;
end try
begin catch
exec proc_error_info; --調用錯誤訊息預存程序
end catch
go

 

     # 樣本:異常能處理的錯誤資訊

--
--簡單try catch樣本,無法處理錯誤
begin try
select * * from student;
end try
begin catch
exec proc_error_info;
end catch
go
--
--簡單try catch樣本,不處理錯誤(不存在的表對象)
begin try
select * from st;
end try
begin catch
exec proc_error_info;
end catch
go
--
--異常處理,能處理預存程序(觸發器)中(不存在表對象)的錯誤資訊
if (object_id(‘proc_select‘) is not null)
drop procedure proc_select
go
create proc proc_select
as
select * from st;
go
begin try
exec proc_select;
end try
begin catch
exec proc_error_info;
end catch
go
  

     異常不能處理編譯期的錯誤,如語法錯誤。以及重編譯造成部分名稱對象得不到正確解析的時候所出現的錯誤。

 

     # 樣本:無法提交的事務

--建立臨時用表
if (object_id(‘temp_tab‘, ‘u‘) is not null)
drop table temp_tab
go
create table temp_tab(
id int primary key identity(100000, 1),
name varchar(200)
)
go

begin try
begin tran;
--沒有createTime欄位
alter table temp_tab drop column createTime;
commit tran;
end try
begin catch
exec proc_error_info;--顯示異常資訊
if (xact_state() = -1)
begin
print ‘會話具有活動事務,但出現了致使事務被歸類為無法提交的事務的錯誤。‘
+ ‘會話無法提交事務或復原到儲存點;它只能請求完全復原事務。‘
+ ‘會話在復原事務之前無法執行任何寫操作。會話在復原事務之前只能執行讀操作。‘
+ ‘交易回復之後,會話便可執行讀寫操作並可開始新的事務。‘;
end
else if (xact_state() = 0)
begin
print ‘會話沒有活動事務。‘;
end
else if (xact_state() = 1)
begin
print ‘會話具有活動事務。會話可以執行任何操作,包括寫入資料和提交事務。‘;
end
end catch
go

 

     # 樣本:處理異常日誌資訊

--
---異常、錯誤資訊表
if (object_id(‘errorLog‘, ‘U‘) is not null)
drop table errorLog
go
create table errorLog(
errorLogID int primary key identity(100, 1), --ErrorLog 行的主鍵。
errorTime datetime default getDate(), --發生錯誤的日期和時間。
userName sysname default current_user, --執行發生錯誤的批處理的使用者。
errorNumber int, --發生的錯誤的錯誤號碼。
errorSeverity int, --發生的錯誤的嚴重性。
errorState int, --發生的錯誤的狀態號。
errorProcedure nvarchar(126), --發生錯誤的預存程序或觸發器的名稱。
errorLine int, --發生錯誤的行號。
errorMessage nvarchar(4000)
)
go
--
--預存程序:添加異常日誌資訊
if (object_id(‘proc_add_exception_log‘, ‘p‘) is not null)
drop proc proc_add_exception_log
go
create proc proc_add_exception_log(@logId int = 0 output)
as
begin
set nocount on;
set @logId = 0;
begin try
if (error_number() is null)
return;

if (xact_state() = -1)
begin
print ‘會話具有活動事務,但出現了致使事務被歸類為無法提交的事務的錯誤。‘
+ ‘會話無法提交事務或復原到儲存點;它只能請求完全復原事務。‘
+ ‘會話在復原事務之前無法執行任何寫操作。會話在復原事務之前只能執行讀操作。‘
+ ‘交易回復之後,會話便可執行讀寫操作並可開始新的事務。‘;
end
else if (xact_state() = 0)
begin
print ‘會話沒有活動事務。‘;
end
else if (xact_state() = 1)
begin
print ‘會話具有活動事務。會話可以執行任何操作,包括寫入資料和提交事務。‘;
end

--添加日誌資訊
insert into errorLog values(getDate(),
current_user, error_number(),
error_severity(), error_state(),
error_procedure(),
error_line(), error_message());
--設定自增值
select @logId = @@identity;
end try
begin catch
print ‘添加異常日誌資訊出現錯誤‘;
exec proc_error_info;--顯示錯誤資訊
return -1;
end catch
end
go
--
---處理異常資訊樣本
declare @id int;
begin try
begin tran;
--刪除帶有外鍵的記錄資訊
delete classes where id = 1;
commit tran;
end try
begin catch
exec proc_error_info;--顯示錯誤資訊
if (xact_state() <> 0)
begin
rollback tran;
end
exec proc_add_exception_log @id output
end catch
select * from errorLog where errorLogID = @id;
go

 

Ø 遊標

     遊標可以對一個select的結果集進行處理,或是不需要全部處理,就會返回一個對記錄集進行處理之後的結果。

     1、遊標實際上是一種能從多條資料記錄的結果集中每次提取一條記錄的機制。遊標可以完成:

          # 允許定位到結果集中的特定行

          # 從結果集的當前位置檢索一行或多行資料

          # 支援對結果集中當前位置的進行修改

     由於遊標是將記錄集進行一條條的操作,所以這樣給伺服器增加負擔,一般在操作複雜的結果集的情況下,才使用遊標。SQL Server 2005有三種遊標:T-SQL遊標、API遊標、用戶端資料指標。

 

     2、遊標的基本操作

          遊標的基本操作有定義遊標、開啟遊標、迴圈讀取遊標、關閉遊標、刪除遊標。

     A、 定義遊標

declare cursor_name    --遊標名稱
cursor [local | global] --全域、局部
[forward only | scroll] --遊標滾動方式
[read_only | scroll_locks | optimistic] --讀取方式
for select_statements --查詢語句
[for update | of column_name ...] --修改欄位

     參數:

     forward only | scroll:前一個參數,遊標只能向後移動;後一個參數,遊標可以隨意移動

     read_only:唯讀遊標

     scroll_locks:遊標鎖定,遊標在讀取時,資料庫會將該記錄鎖定,以便遊標完成對記錄的操作

     optimistic:該參數不會鎖定遊標;此時,如果記錄被讀入遊標後,對遊標進行更新或刪除不會超過

 

     B、 開啟遊標

          open cursor_name;

          遊標開啟後,可以使用全域變數@@cursor_rows顯示讀取記錄條數

 

     C、 檢索遊標

          fetch cursor_name;

          檢索方式如下:

             fetch first; 讀取第一行

             fetch next; 讀取下一行

             fetch prior; 讀取上一行

             fetch last; 讀取最後一行

             fetch absolute n; 讀取某一行

                如果n為正整數,則讀取第n條記錄

                如果n為負數,則倒數提取第n條記錄

                如果n為,則不讀取任何記錄

             fetch pelative n

                如果n為正整數,則讀取上次讀取記錄之後第n條記錄

                如果n為負數,則讀取上次讀取記錄之前第n條記錄

                如果n為,則讀取上次讀取的記錄

 

     D、 關閉遊標

          close cursor_name;

 

     E、 刪除遊標

          deallocate cursor_name;

 

     3、遊標操作樣本

--建立一個遊標
declare cursor_stu cursor scroll for
select id, name, age from student;
--開啟遊標
open cursor_stu;
--儲存讀取的值
declare @id int,
@name nvarchar(20),
@age varchar(20);
--讀取第一條記錄
fetch first from cursor_stu into @id, @name, @age;
--迴圈讀取遊標記錄
print ‘讀取的資料如下:‘;
--全域變數
while (@@fetch_status = 0)
begin
print ‘編號:‘ + convert(char(5), @id) + ‘, 名稱:‘ + @name + ‘, 類型:‘ + @age;
--繼續讀取下一條記錄
fetch next from cursor_stu into @id, @name, @age;
end
--關閉遊標
close area_cursor;

--刪除遊標
--deallocate area_cursor;

轉載自:http://www.cnblogs.com/hoojo/archive/2011/07/19/2110325.html
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.