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(已經提交讀隔離)版本控制