筆記47-徐 數據庫引擎中基於行版本控制的隔離級別

筆記47-徐 數據庫引擎中基於行版本控制的隔離級別

MSSQL隔離級別
READ UNCOMMITTED(未提交讀),至關於(NOLOCK)
READ COMMITTED(已提交讀,默認)
REPEATABLE READ(可重複讀),至關於(HOLDLOCK)
SERIALIZABLE(序列化)
MVCC
SNAPSHOT(快照):能夠防止幻讀,可重複讀
READ COMMITTED SNAPSHOT(已提交讀快照):不可防止幻讀,可重複讀html

 

參考:https://www.cnblogs.com/lyhabc/articles/3996187.html  (MICROSOFT SQL SERVER 2008技術內幕:T-SQL語言基礎 筆記)mysql

  1 --數據庫引擎中基於行版本控制的隔離級別
  2 
  3 --在SQL標準的已提交讀(read committed)隔離級別下,一個讀操做會和一個寫操做
  4 --相互阻塞。未提交讀(read uncommitted)雖然不會有這種阻塞,可是讀操做可能
  5 --會讀到髒數據,這是大部分用戶不能接受的。有些關係型數據庫(例如ORACLE)
  6 --使用的是另外一種處理方式。在任何一個修改以前,先對修改前的版本作一個複製,
  7 --後續的一切讀操做都會去讀這個複製的版本,修改將建立一個新的版本。在這種
  8 --處理方式下,讀,寫操做不會互相阻塞。使用這種行版本控制機制的好處,是
  9 --程序的併發性比較高,可是缺點是用戶讀到的雖然不是一個髒數據,可是可能
 10 --是個正在被修改立刻就要過時的數據值。若是根據這個過時的值作數據修改,
 11 --會產生邏輯錯誤。
 12 
 13 --有些用戶可能爲了更高的併發性而不在意這種缺點,因此更喜歡ORACLE的那種
 14 --處理方法。爲了知足這部分用戶的需求,SQL2005也引入了這種機制,來實現
 15 --相似的功能。因此選取行版本控制隔離級別也能夠成爲消除阻塞和死鎖的一種
 16 --手段
 17 
 18 --SQL有兩種行版本控制:
 19 --(1)行版本控制的已提交讀隔離(read_committed_snapshot)
 20 --(2)直接使用snapshot事務隔離級別
 21 
 22 --(1)(read_committed_snapshot):read_committed_snapshot數據庫選項爲ON時,read_committed事務經過使用行
 23 --版本控制提供語句級讀取一致性
 24 
 25 --(2)(snapshot事務隔離級別)allow_snapshot_isolation數據庫選項爲ON時,snapshot事務經過使用行版本
 26 --控制提供事務級讀取一致性
 27 
 28 
 29 --下列示例能夠說明使用普通已提交讀事務,行版本控制的快照隔離事務和行版本
 30 --控制的已提交讀事務的行爲差別
 31 
 32 --示例:
 33 
 34 --A 普通已提交事務
 35 --在此示例中,一個普通read committed事務將讀取數據,而後由另外一事務修改此數據。執行
 36 --完的讀操做不阻塞由其餘事務執行的更新操做。可是,在其餘事務已經作了更新操做後,讀
 37 --操做會被阻塞住,直到更新操做事務提交爲止
 38 
 39 --在會話1上:
 40 USE [AdventureWorks]
 41 GO
 42 BEGIN TRAN
 43 --查詢1
 44 --這個查詢將返回員工有48小時休假時間
 45 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
 46 
 47 -----------------------------------------------------------------------------------------------
 48 
 49 --在會話2上:
 50 USE [AdventureWorks]
 51 GO
 52 BEGIN TRAN
 53 --修改1
 54 --休假時間減去8
 55 --修改不會被阻塞,由於會話1不會持有S鎖不放
 56 UPDATE [HumanResources].[Employee]
 57 SET [VacationHours]=[VacationHours]-8
 58 WHERE [EmployeeID]=4
 59 
 60 --查詢1
 61 --如今休假時間只有40小時
 62 SELECT [VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
 63 
 64 --------------------------------------------------------------------------------------------------
 65 
 66 
 67 --在會話1上:
 68 --從新運行查詢語句,會被會話2阻塞
 69 --查詢2
 70 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
 71 
 72 -----------------------------------------------------------------------------------------------
 73 
 74 --在會話2上:
 75 --提交事務
 76 COMMIT TRAN
 77 GO
 78 
 79 -----------------------------------------------------------------------------------------------
 80 
 81 --在會話1上:
 82 --此時先前被阻塞的查詢結束,返回會話2修改好的新數據:40
 83 --查詢3
 84 --這裏返回40,由於會話2已經提交了事務
 85 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
 86 
 87 --修改2
 88 --這裏會成功
 89 UPDATE [HumanResources].[Employee]
 90 SET [SickLeaveHours]=[SickLeaveHours]-8
 91 WHERE [EmployeeID]=4
 92 
 93 SELECT [SickLeaveHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
 94 
 95 --能夠回滾會話1的修改
 96 --會話2的修改不會受影響
 97 ROLLBACK TRAN

 98 GO
 99 
100 SELECT [SickLeaveHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
101 -------------------------------------------------------------------------------------------
102 
103 
104 --B 使用快照隔離
105 --此示例中,在快照隔離下運行的事務將讀取數據,而後由另外一個事務修改此數據。快照事務
106 --不阻塞由其餘事務執行的更新操做,他忽略數據的修改繼續從版本化的行讀取數據。也就是
107 --說,讀取到的是數據修改前的版本。可是,當快照事務嘗試修改已由其餘事務修改的數據時,
108 --他將生成錯誤並終止
109 
110 --在會話1上:
111 USE [AdventureWorks]
112 GO
113 
114 --啓用快照隔離
115 ALTER DATABASE [AdventureWorks] SET ALLOW_SNAPSHOT_ISOLATION ON
116 GO
117 
118 --設置使用快照隔離級別
119 SET TRANSACTION ISOLATION LEVEL SNAPSHOT
120 GO
121 
122 BEGIN TRAN
123 --查詢1
124 --查詢返回員工有48小時假期
125 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
126 ---------------------------------------------------------------------------------------------
127 
128 --在會話2上:
129 USE [AdventureWorks]
130 GO
131 
132 BEGIN TRAN
133 --修改1
134 --假期時間減8
135 --修改不會被會話1阻塞
136 UPDATE [HumanResources].[Employee]
137 SET [VacationHours]=[VacationHours]-8
138 WHERE [EmployeeID]=4
139 
140 --查詢1
141 --確認值已經被改爲40
142 SELECT [VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
143 
144 -----------------------------------------------------------------------------------------------
145 
146 --在會話1上:
147 --查詢2
148 --再次運行查詢語句
149 --仍是返回48(修改前的值),由於會話1是從版本化的行讀取數據
150 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
151 
152 ------------------------------------------------------------------------------------------------
153 
154 --在會話2上:
155 --提交事務
156 COMMIT TRAN
157 GO
158 
159 -------------------------------------------------------------------------------------------------
160 
161 --在會話1上:
162 --查詢3
163 --再次運行查詢語句
164 --仍是返回48(修改前的值),由於會話1仍是從版本化的行讀取數據
165 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
166 
167 --修改2
168 --由於數據已經被會話2修改過,會話1想作任何修改時
169 --會遇到3960錯誤
170 --事務會自動回滾
171 UPDATE [HumanResources].[Employee]
172 SET [SickLeaveHours]=[SickLeaveHours]-8
173 WHERE  [EmployeeID]=4
174 
175 --會話1的修改會回滾
176 --會話2的修改不會回滾
177 ROLLBACK TRAN
178 GO
179 
180 ----------------------------------------------------------------------------------------------
181 
182 
183 
184 --C 使用行版本控制的已提交讀
185 --在此示例中,使用行版本控制的已提交讀事務與其餘事務併發運行。已提交讀事務的行爲與快照事務的行爲
186 --有所不一樣。與快照事務相同的是,即便其餘事務修改了數據,已提交讀事務也將讀取版本化的行。
187 --與快照事務不一樣的是,已提交讀將執行下列操做:
188 
189 --(1)在其餘事務提交數據更改以後,讀取修改的數據
190 --(2)可以更新由其餘事務修改的數據,而快照事務不能
191 
192 --在會話1上:
193 USE [AdventureWorks]
194 GO
195 --啓用行版本控制的已提交讀
196 --注意運行這句話的時候,不能夠有其餘鏈接同時使用[AdventureWorks]
197 ALTER DATABASE [AdventureWorks] SET READ_COMMITTED_SNAPSHOT ON
198 GO
199 
200 --設置使用已提交讀隔離級別
201 SET TRANSACTION ISOLATION LEVEL READ COMMITTED
202 GO
203 
204 BEGIN TRAN
205 --查詢1
206 --這裏將返回初始值48
207 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
208 
209 ----------------------------------------------------------------------------------------------------
210 
211 --在會話2上:
212 USE [AdventureWorks]
213 GO
214 
215 BEGIN TRAN
216 --修改1
217 --假期時間減8
218 --修改不會被會話1阻塞
219 UPDATE [HumanResources].[Employee]
220 SET [VacationHours]=[VacationHours]-8
221 WHERE [EmployeeID]=4
222 
223 --查詢1
224 --確認值已經被修改成40
225 SELECT [VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
226 
227 ------------------------------------------------------------------------------------------------
228 
229 --在會話1上:
230 --查詢2
231 --再次運行查詢語句
232 --仍是返回48(修改前的值),由於會話2尚未提交
233 --會話1是從版本化的行讀取數據
234 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
235 
236 -------------------------------------------------------------------------------------------------
237 
238 --在會話2上:
239 --提交事務
240 COMMIT TRAN
241 GO
242 --------------------------------------------------------------------------------------------------
243 
244 --在會話1上:
245 --查詢3
246 --這裏和範例B不一樣,會話1始終返回已提交的值
247 --這裏返回40,由於會話2已經提交了事務
248 SELECT [EmployeeID],[VacationHours] FROM [HumanResources].[Employee] WHERE [EmployeeID]=4
249 
250 --修改2
251 --這裏會成功
252 UPDATE [HumanResources].[Employee]
253 SET [SickLeaveHours]=[SickLeaveHours]-8
254 WHERE [EmployeeID]=4
255 
256 --能夠回滾會話1的修改
257 --會話2的修改不會受影響
258 ROLLBACK TRAN
259 GO
260 
261 
262 ------------------------------------------結論-----------------------------------------------------------
263 --從上面的測試結果能夠看到,原先會發生阻塞的兩個會話在使用行版本控制的隔離級別後,都不會遇到阻塞了。
264 --可是兩種行版本控制的結果又有不一樣
265 
266 --可是行版本控制並非消除阻塞和死鎖的萬靈藥。在決定使用以前,必須考慮下面兩個問題
267 
268 --(1)最終用戶是否接受行版本控制下的運行結果?  行版本控制:數據庫級別
269 --上面的3個測試返回的結果都各有不一樣。在不一樣的事務階段,有的被阻塞住,有的讀到的是舊版本值,
270 --有的讀到新版本值。用戶指望的行爲是什麼?他是但願哪怕被阻塞住也要讀到最新版本數據,仍是
271 --能容忍讀到舊版本數據呢?某些應用程序依賴於讀隔離的鎖定和阻塞行爲,例如生成一個串行的流水號
272 --之類的操做。改爲行版本控制,原先的處理邏輯就不能正常工做了。因此在採用新的隔離級別以前,
273 --必定要作好測試,確保應用按預期的邏輯運行
274 
275 
276 
277 
278 --(2)SQL是否能支持行版本控制帶來的額外負荷?
279 --開啓了行版本控制以後,SQL會把行版本存放在tempdb裏。修改的數據越多,須要存儲的信息越多
280 --對SQL額外的負載就越大。因此若是一個應用要從其餘隔離級別轉向使用行版本控制,須要作特別
281 --的測試,以確保現有的軟硬件配置能支持額外的負荷,應用程序可以達到類似的響應速度

 

對於庫存類業務,嚴格按照串行方式執行的,那麼建議使用SNAPSHOT(快照,也叫全快照隔離級別),在SNAPSHOT(快照)下面,別的事務要等修改數據的那個事務運行完才能修改,保證串行,缺點是別的事務沒有重試機制的話
會形成更新丟失sql

對於庫存類業務,不建議使用READ COMMITTED SNAPSHOT(已經提交讀隔離),不保證串行方式執行,兩個事務能夠同時修改同一行數據,A事務讀的是當前版本,B事務讀的是歷史版本,同時修改的時候,會形成數據錯亂
由於B事務修改的是歷史版本數據數據庫

RDS-SQLSERVER的READ COMMITTED與READ_COMMITTED_SNAPSHOT的區別及各自優缺點
解剖SQLSERVER 第一篇 數據庫恢復軟件商的黑幕(有刪減版)
https://www.cnblogs.com/lyhabc/p/3900229.html
https://www.cnblogs.com/lyhabc/articles/3967438.html併發

 

更新丟失更清楚的解釋:https://www.2cto.com/database/201609/547323.htmlmvc

 

SQL Server實現了SQL99定義的四個標準隔離級別,而且額外實現了兩個快照隔離級別
須要說明的是,不一樣的DBMS的默認隔離級別和對隔離級別的實現是不徹底同樣的,也不必定是徹底按照SQL99定義的四個標準隔離級別來實現的測試

 

下面兩種是mssql增長的爲了兼容mvcc特性而增長的隔離級別,mysql默認就支持mvcc,因此不會有下面兩種隔離級別spa

SNAPSHOT(快照)
READ COMMITTED SNAPSHOT(已經提交讀隔離)版本控制

相關文章
相關標籤/搜索