了解事務和鎖
事務:保持邏輯數據一致性與可恢復性,必不可少的利器。
鎖:多用戶訪問同一數據庫資源時,對訪問的先后次序權限管理的一種機制,沒有他事務或許將會一塌糊塗,不能保證數據的安全正確讀寫。
死鎖:是數據庫性能的重量級殺手之一,而死鎖卻是不同事務之間搶占數據資源造成的。
一個事務中可以包含多個DML語句,一個DDL語句或者一個DCL語句。
事務中的語句要么全部執行,要么全部不執行。
書面解釋:事務具有原子性,一致性,隔離性,持久性(ACID)
- A 原子性:事務必須是一個自動工作的單元,要么全部執行,要么全部不執行。
- C 一致性:事務把數據庫從一個一致狀態帶入到另一個一致狀態,事務結束的時候,所有的內部數據都是正確的。
- I 隔離性:並發多個事務時,一個事務的執行不受其他事務的影響。
- D 持久性:事務提交之后,數據是永久性的,不可再回滾,不受關機等事件的影響。
事務在如下情況終止:
- 遇到rollback 或commit命令
- 遇到DDL或者DCL語句.
- 系統發生錯誤,崩潰或者退出。
然而在SQL Server中事務被分為3類常見的事務:
- 自動提交事務:是SQL Server默認的一種事務模式,每條Sql語句都被看成一個事務進行處理,你應該沒有見過,一條Update 修改2個字段的語句,只修該了1個字段而另外一個字段沒有修改。。
- 顯式事務:T-sql標明,由Begin Transaction開啟事務開始,由Commit Transaction 提交事務、Rollback Transaction 回滾事務結束。
- 隱式事務:使用Set IMPLICIT_TRANSACTIONS ON 將將隱式事務模式打開,不用Begin Transaction開啟事務,當一個事務結束,這個模式會自動啟用下一個事務,只用Commit Transaction 提交事務、Rollback Transaction 回滾事務即可
顯式事務的應用
常用語句就四個。
- Begin Transaction:標記事務開始。
- Commit Transaction:事務已經成功執行,數據已經處理妥當。
- Rollback Transaction:數據處理過程中出錯,回滾到沒有處理之前的數據狀態,或回滾到事務內部的保存點。
- Save Transaction:事務內部設置的保存點,就是事務可以不全部回滾,只回滾到這里,保證事務內部不出錯的前提下。
---開啟事務
begin tran
--錯誤捕捉機制,看好啦,這里也有的。並且可以嵌套。
begin try --語句正確
insert into lives (Eat,Play,Numb) values ('豬肉','足球',1) --Numb為int類型,出錯
insert into lives (Eat,Play,Numb) values ('豬肉','足球','abc') --語句正確
insert into lives (Eat,Play,Numb) values ('狗肉','籃球',2) end try begin catch select Error_number() as ErrorNumber, --錯誤代碼
Error_severity() as ErrorSeverity, --錯誤嚴重級別,級別小於10 try catch 捕獲不到
Error_state() as ErrorState , --錯誤狀態碼
Error_Procedure() as ErrorProcedure , --出現錯誤的存儲過程或觸發器的名稱。
Error_line() as ErrorLine, --發生錯誤的行號
Error_message() as ErrorMessage --錯誤的具體信息
if(@@trancount>0) --全局變量@@trancount,事務開啟此值+1,他用來判斷是有開啟事務
rollback tran ---由於出錯,這里回滾到開始,第一條語句也沒有插入成功。
end catch if(@@trancount>0) commit tran --如果成功Lives表中,將會有3條數據。
--表本身為空表,ID ,Numb為int 類型,其它為nvarchar類型
select * from lives
事務設置保存點
利用save transaction 和rollback transaction 語句,
---開啟事務
begin tran
--錯誤捕捉機制,看好啦,這里也有的。並且可以嵌套。
begin try --語句正確
insert into lives (Eat,Play,Numb) values ('豬肉','足球',1) --加入保存點
save tran pigOneIn
insert into lives (Eat,Play,Numb) values ('豬肉','足球',2)
insert into lives (Eat,Play,Numb) values ('狗肉','籃球',3) end try begin catch select Error_number() as ErrorNumber, --錯誤代碼
Error_severity() as ErrorSeverity, --錯誤嚴重級別,級別小於10 try catch 捕獲不到
Error_state() as ErrorState , --錯誤狀態碼
Error_Procedure() as ErrorProcedure , --出現錯誤的存儲過程或觸發器的名稱。
Error_line() as ErrorLine, --發生錯誤的行號
Error_message() as ErrorMessage --錯誤的具體信息
if(@@trancount>0) --全局變量@@trancount,事務開啟此值+1,他用來判斷是有開啟事務
rollback tran
end catch if(@@trancount>0) rollback tran pigOneIn
--表本身為空表,ID ,Numb為int 類型,其它為nvarchar類型
select * from lives
注:事務保存點以上的都將影響,當提交事務以后,只有保存點之前的語句被執行。
事務保存點示例:
在SQL Server中使用rollback會回滾所有的未提交事務狀態,但是有些時候我們只需要回滾部分語句,把不需要回滾的語句提到事務外面來,雖然是個方法,但是卻破壞了事務的ACID。
SQL中使用事務保存點,即可解決這個問題。
SQL 事務中存在錯誤信息 進行Catch 回滾事務時
begin try begin tran A insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'A', '', 0, getdate() ) select 1/0 --錯誤信息
save tran B_Point insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'B', '', 0, getdate() ) save tran C_Point insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'C', '', 0, getdate() ) rollback tran B_Point --回滾事務點B_Point 即事務點下的部分都回滾
select 1
commit tran A --提交整個事務信息
end try begin catch select 2
rollback tran B_Point --回滾事務點B_Point 即事務點下的部分都回滾
commit tran A --提交整個事務信息
end catch go
select * from dbo.lives go
SQL回滾局部信息時
begin try begin tran A insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'A', '', 0, getdate() ) --select 1/0 --錯誤信息
save tran B_Point insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'B', '', 0, getdate() ) save tran C_Point insert into dbo.lives ( Eat, Play, Numb, times ) values ( 'C', '', 0, getdate() ) rollback tran B_Point --回滾事務點B_Point 即事務點下的部分都回滾
select 1
commit tran A --提交整個事務信息
end try begin catch select 2
rollback tran B_Point --回滾事務點B_Point 即事務點下的部分都回滾
commit tran A --提交整個事務信息
end catch go
select * from dbo.lives go
回滾保存點B時 即保存點以下部分均要回滾,
注:使用保存點 無論try 或 catch 代碼塊 除提交或回滾保存點外,都要COMMIT或 ROLLBACK完整事務。
使用場景:當操作數據時前校驗數據成本太高且數據出錯率不高時 可采用.eg:用戶下單 檢查庫存信息是否>0時 可以設置庫存量需>=0的約束 當更新庫時信息小於0即出錯 進行事務回滾 並查詢返回當前庫存信息
使用set xact_abort
設置 xact_abort on/off , 指定是否回滾當前事務,為on時如果當前sql出錯,回滾整個事務,為off時如果sql出錯回滾當前sql語句,其它語句照常運行讀寫數據庫。
delete lives --清空數據
set xact_abort off
begin tran
--語句正確
insert into lives (Eat,Play,Numb) values ('豬肉','足球',1) --Numb為int類型,出錯,如果1234..那個大數據換成'132dsaf' xact_abort將失效
insert into lives (Eat,Play,Numb) values ('豬肉','足球',12345646879783213) --語句正確
insert into lives (Eat,Play,Numb) values ('狗肉','籃球',3) commit tran
select * from lives
為on時,結果集為空,因為運行是數據過大溢出出錯,回滾整個事務。