.NET:臟讀、不可重復讀和幻讀代碼示例


並發可能產生的三種問題(測試代碼

臟讀

定義:A事務執行過程中B事務讀取了A事務的修改,但是A事務並沒有結束(提交),A事務后來可能成功也可能失敗。

比喻:A修改了源代碼並且並沒有提交到源代碼系統,A直接通過QQ將代碼發給了B,A后來取消了修改。

代碼示例

 1         [TestMethod]
 2         public void 臟讀_測試()
 3         {
 4             //前置條件
 5             using (var context = new TestEntities())
 6             {
 7                 Assert.AreEqual(1, context.Tables.Count());
 8             }
 9 
10             var autoResetEvent = new AutoResetEvent(false);
11 
12             var transactionOptions1 = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
13             var transactionOptions2 = new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted };
14 
15             using (var ts1 = new TransactionScope(TransactionScopeOption.Required, transactionOptions1))
16             {
17                 //添加數據
18                 using (var context = new TestEntities())
19                 {
20                     context.Tables.Add(new Table() { Id = Guid.NewGuid(), Name = "段光偉" });
21                     context.SaveChanges();
22                 }
23 
24                 ThreadPool.QueueUserWorkItem(data =>
25                 {
26                     using (var ts2 = new TransactionScope(TransactionScopeOption.Required, transactionOptions2))
27                     {
28                         //臟讀測試
29                         using (var context = new TestEntities())
30                         {
31                             Assert.AreEqual(2, context.Tables.Count());
32                         }
33                     }
34 
35                     autoResetEvent.Set();
36                 });
37 
38                 autoResetEvent.WaitOne();
39             }
40 
41             //后置條件
42             using (var context = new TestEntities())
43             {
44                 Assert.AreEqual(1, context.Tables.Count());
45             }
46         }

不可重復讀

定義:A事務讀取了兩次數據,在這兩次的讀取過程中B事務修改了數據,A事務的這兩次讀取出來的數據不一樣了(不可重復讀)。

比喻:A在做源代碼審查,在審查的過程中獲取了兩次源代碼,在這兩次獲取期間B修改了源代碼,B修改的很可能是A審查過的代碼,而這部分代碼可能不符合規范了。

代碼示例

 1         [TestMethod]
 2         public void 不可重復讀_測試()
 3         {
 4             var autoResetEvent = new AutoResetEvent(false);
 5 
 6             var transactionOptions1 = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
 7             var transactionOptions2 = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
 8 
 9             using (var ts1 = new TransactionScope(TransactionScopeOption.Required, transactionOptions1))
10             {
11                 //前置條件
12                 using (var context = new TestEntities())
13                 {
14                     Assert.AreEqual("李妞妞", context.Tables.First().Name);
15                 }
16 
17                 ThreadPool.QueueUserWorkItem(data =>
18                 {
19                     using (var ts2 = new TransactionScope(TransactionScopeOption.Required, transactionOptions2))
20                     {
21                         //修改數據
22                         using (var context = new TestEntities())
23                         {
24                             context.Tables.First().Name = "段光偉";
25                             context.SaveChanges();
26                         }
27 
28                         ts2.Complete();    
29                     }
30 
31                     autoResetEvent.Set();
32                 });
33 
34                 autoResetEvent.WaitOne();
35 
36                 //不可重復讀測試
37                 using (var context = new TestEntities())
38                 {
39                     Assert.AreEqual("段光偉", context.Tables.First().Name);
40                 }
41             }
42         }

幻讀

定義:A事務讀取了兩次數據,在這兩次的讀取過程中B事務添加了數據,A事務的這兩次讀取出來的集合不一樣了(幻讀)。

比喻:A在統計文件數據,為了統計精確A統計了兩次,在這兩次的統計過程中B添加了一個文件,A發現這兩次統計的數量不一樣(幻讀),A會感覺自己的腦袋有點頭疼。

代碼示例

 1         [TestMethod]
 2         public void 幻讀_測試()
 3         {
 4             var autoResetEvent = new AutoResetEvent(false);
 5 
 6             var transactionOptions1 = new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead };
 7             var transactionOptions2 = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted };
 8 
 9             using (var ts1 = new TransactionScope(TransactionScopeOption.Required, transactionOptions1))
10             {
11                 //前置條件
12                 using (var context = new TestEntities())
13                 {
14                     Assert.AreEqual(1, context.Tables.Count());
15                 }
16 
17                 ThreadPool.QueueUserWorkItem(data =>
18                 {
19                     using (var ts2 = new TransactionScope(TransactionScopeOption.Required, transactionOptions2))
20                     {
21                         //添加數據
22                         using (var context = new TestEntities())
23                         {
24                             context.Tables.Add(new Table() { Id = Guid.NewGuid(), Name = "段光偉" });
25                             context.SaveChanges();
26                         }
27 
28                         ts2.Complete();
29                     }
30 
31                     autoResetEvent.Set();
32                 });
33 
34                 autoResetEvent.WaitOne();
35 
36                 //幻讀測試
37                 using (var context = new TestEntities())
38                 {
39                     Assert.AreEqual(2, context.Tables.Count());
40                 }
41             }
42         }

四種隔離級別如何處理並發問題

  臟讀 不可重復讀 幻讀
讀未提交 允許 允許 允許
讀已提交 不允許 允許 允許
可重復讀 不允許 不允許 允許
串行化 不允許 不允許 不允許

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM