1.事務的四個屬性 原子性Atomicity,一致性Consistency,隔離性Isolation,持久性Durability ,即ACID特性。 原子性:事務必須是一個完整工作的單元,要麼全部執行,要麼全部不執行。 一致性:事務結束的時候,所有的內部數據都是正確的。 隔離性:併發多個事務時,各個 ...
1.事務的四個屬性
原子性Atomicity,一致性Consistency,隔離性Isolation,持久性Durability ,即ACID特性。
原子性:事務必須是一個完整工作的單元,要麼全部執行,要麼全部不執行。
一致性:事務結束的時候,所有的內部數據都是正確的。
隔離性:併發多個事務時,各個事務不幹涉內部數據,處理的都是另外一個事務處理之前或之後的數據。
持久性:事務提交之後,數據是永久性的,不可再回滾。
2.在SQL Server中事務被分為3類常見的事務
自動提交事務:是SQL Server預設的一種事務模式,每條Sql語句都被看成一個事務進行處理。如果成功執行,則自動提交,如果錯誤,則自動回滾。
顯式事務:T-sql標明,由Begin Transaction開啟事務開始,由Commit Transaction 提交事務、Rollback Transaction 回滾事務結束。
隱式事務:使用Set IMPLICIT_TRANSACTIONS ON 將將隱式事務模式打開,不用Begin Transaction開啟事務。當一個事務結束,這個模式會自動啟用下一個事務,只用Commit Transaction 提交事務、Rollback Transaction 回滾事務即可。
3.事物的語法
Begin Transaction:標記事務開始。
Commit Transaction:事務已經成功執行,數據已經處理妥當。
Rollback Transaction:數據處理過程中出錯,回滾到沒有處理之前的數據狀態,或回滾到事務內部的保存點。
Save Transaction:事務內部設置的保存點,就是事務可以不全部回滾,只回滾到這裡,保證事務內部不出錯的前提下。
4.示例
---開啟事務
begin tran
begin try --在這裡我們可以添加錯誤的撲捉機制
insert into A(id,name,typeid) values (1,'小王',1) --語句正確
-- save tran pigOneIn --在這裡我們可以添加保存點,保存之前正確的數據
insert into A(id,name,typeid) values (2,'小李','學生') --語句類型錯誤
insert into A(id,name,typeid) values (1,'小張',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 --出錯回滾,A表中0條數據
-- rollback tran pigOneIn --出錯回滾,A表中1條數據
end catch
if(@@trancount>0)
commit tran
SELECT * FROM A --如果成功A表中,將會有3條數據。
5.使用set xact_abort
指定是否回滾當前事務(xact_abort on/off) , 為on時,如果當前sql出錯,回滾整個事務,為off時,如果sql出錯回滾當前sql語句,其它語句照常運行讀寫資料庫。
註意:xact_abort只對運行時出現的錯誤有用,如果sql語句本身存在錯誤,那麼xact_abort就沒用了。
示例:
set xact_abort off
begin tran
insert into A(id,name,typeid) values (1,'小王',1) --語句正確
insert into A(id,name,typeid) values (2,'小李',12313212313212313) --算術溢出錯誤,將插入其他兩條。如果這裡是'學生', xact_abort將失效,不插入任何數據
insert into A(id,name,typeid) values (1,'小張',2) --語句正確
commit tran
select * from A
6.事物併發
在多用戶都用事務同時訪問同一個數據資源的情況下,就會造成以下幾種數據錯誤。
更新丟失:多個用戶同時對一個數據資源進行更新,必定會產生被覆蓋的數據,造成數據讀寫異常。
不可重覆讀:如果一個用戶在一個事務中多次讀取一條數據,而另外一個用戶則同時更新啦這條數據,造成第一個用戶多次讀取數據不一致。
臟讀:第一個事務讀取第二個事務正在更新的數據表,如果第二個事務還沒有更新完成,那麼第一個事務讀取的數據將是一半為更新過的,一半還沒更新過的數據,這樣的數據毫無意義。
幻讀:第一個事務讀取一個結果集後,第二個事務,對這個結果集經行增刪操作,然而第一個事務中再次對這個結果集進行查詢時,數據發現丟失或新增
我們用鎖定正在操作的數據,來解決這些問題,當一個事務對一些數據塊進行操作的時候,另外一個事務則不能插足這些數據塊。
鎖定從資料庫角度看大致可以分為6種:
共用鎖(S):用於讀操作(SELECT),還可以叫它讀鎖。多個事務可以併發讀取數據,但任何事務都不能修改數據,直到數據讀取完成,共用鎖釋放。S鎖通常數據被讀取完畢,立即被釋放。
排它鎖(X):用於寫操作( INSERT、DELETE),還可以叫他獨占鎖、寫鎖。僅允許一個事務處理數據,也就是說如果你對數據資源進行增刪改的操作時,其它任何事務不允許操作這塊資源,直到排它鎖被釋放,防止同時對同一資源進行多重操作。X鎖一直到事務結束才能被釋放。
更新鎖(U):用來預定要對此頁施加X鎖,它允許其它事務讀,但不允許再施加U。U鎖是為了防止出現死鎖模式,當兩個事務對一個數據資源進行先讀取在修改的情況下,使用共用鎖和排它鎖有時會出現死鎖現象,而使用更新鎖則可以避免死鎖的出現。資源的更新鎖一次只能分配給一個事務,如果需要對資源進行修改,更新鎖會變成排他鎖,否則變為共用鎖。U鎖一直到事務結束時才能被釋放。
意向鎖:SQL Server需要在層次結構中的底層資源上(如行,列)獲取共用鎖,排它鎖,更新鎖。例如表級放置了意 向共用鎖,就表示事務要對錶的頁或行上使用共用鎖。在表的某一行上上放置意向鎖,可以防止其它事務獲取其它不相容的的鎖。意向鎖可以提高性能,因為數據引 擎不需要檢測資源的每一列每一行,就能判斷是否可以獲取到該資源的相容鎖。意向鎖包括三種類型:意向共用鎖(IS),意向排他鎖(IX),意向排他共用鎖 (SIX)。
架構鎖:防止修改表結構時,併發訪問的鎖。
大容量更新鎖:允許多個線程將大容量數據併發的插入到同一個表中,在載入的同時,不允許其它進程訪問該表。
這些鎖之間的相互相容性,也就是,是否可以同時存在。
現有的授權模式 | ||||||
請求的模式 | IS | S | U | IX | SIX | X |
意向共用 (IS) | 是 | 是 | 是 | 是 | 是 | |
共用 (S) | 是 | 是 | 是 | |||
更新 (U) | 是 | 是 | ||||
意向排他 (IX) | 是 | 是 | ||||
意向排他共用 (SIX) | 是 | |||||
排他 (X) |
7.死鎖
死鎖是指在一組進程中的各個進程均占有不會釋放的資源,但因互相申請被其他進程所站用不會釋放的資源而處於的一種永久等待狀態。
減少死鎖的方法大致有一下幾種:
按同一順序訪問對象:併發事務按同一順序訪問對象,則發生死鎖的可能性會降低。
保持事務簡短:儘量不要讓一個事務處理過於複雜的讀寫操作,事務過於複雜,占用資源會增多,處理時間增長,併發執行事物通常會發生死鎖。
避免事務中的用戶交互:儘量不要在事務中要求用戶響應,因為事務持有的任何鎖只有在事務提交或回滾後才會釋放,等待用戶響應的時間,容易導致阻塞或死鎖。
減少併發量及占用時間長的數據操作:儘量減少資料庫的併發量,減少事務長時間等待。
使用較低的隔離級別:使用較低的隔離級別比使用較高的隔離級別持有共用鎖的時間更短。這樣就減少了鎖爭用。註意:先確定事務是否能在較低的隔離級別上運行。
使用基於行版本控制的隔離級別:如果將 READ_COMMITTED_SNAPSHOT 資料庫選項設置為 ON,則在已提交讀隔離級別下運行的事務在讀操作期間將使用行版本控制而不是共用鎖。
8.為事務設置隔離級別
所謂事物隔離級別,就是併發事務對同一資源的讀取深度層次。分為5種。
read uncommitted:這個隔離級別最低啦,可以讀取到一個事務正在處理的數據,但事務還未提交,這種級別的讀取叫做臟讀。
read committed:這個級別是預設選項,不能臟讀,不能讀取事務正在處理沒有提交的數據,但能修改。
repeatable read:不能讀取事務正在處理的數據,也不能修改事務處理數據前的數據。
snapshot:指定事務在開始的時候,就獲得了已經提交數據的快照,因此當前事務只能看到事務開始之前對數據所做的修改。
serializable:最高事務隔離級別,只能看到事務處理之前的數據。
語法
set tran isolation level <級別>
示例1:read uncommitted
begin tran
set deadlock_priority low
update A set name='小王1' where id=1 --原數據小王
waitfor delay '0:0:5' --等待5秒執行下麵的語句
rollback tran
set tran isolation level read uncommitted
select * from A --讀取的數據為正在修改的數據 ,臟讀
waitfor delay '0:0:5' --5秒之後數據已經回滾
select * from A --回滾之後的數據
得到 name='小王'。
示例2:read committed
begin tran
update A set name='小王'
waitfor delay '0:0:10' --等待10秒執行下麵的語句
rollback tran
set tran isolation level read committed
select * from A --獲取不到A,不能臟讀
update A set name='小王2' where id=1 --可以修改
waitfor delay '0:0:10' --10秒之後上一個事務已經回滾
select * from A--修改之後的數據,而不是A
得到 name='小王2'。