Isolation Level 測試 ReadCommitted

Isolation Level ReadCommitted

如果對 transaction isolation 不太清楚可以先看 https://openhome.cc/Gossip/HibernateGossip/IsolationLevel.html

各種 Isolation Level 能解決的問題

 

Dirty Read

Unrepeatable Read

Phantom Read

Read uncommitted        O                O            O
Read committed        X                O            O
Repreatable read        X                X            O
Serializable        X                X            X
Read committed

保證不會    DirtyRead    =>    讀到別的Transaction還沒Commit的資料

作法   =>   如果資料被其他Transaction更新,要等人家Commit完才能讀

請注意兩個 function 都是 async

FirstTransaction 會去更新資料,等10秒後才 commit

SecondTransaction 會去讀 FirstTransaction 還沒 commit 的資料

        private static void Main(string[] args)
        {
            FirstTransaction();

            //確保 FirstTransaction 跑完
            Task.Delay(new TimeSpan(0, 0, 2)).Wait();

            SecondTransaction();

            Console.ReadKey();
        }

        private static async Task FirstTransaction()
        {
            using (var ts = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                // 設定 level
                { IsolationLevel = IsolationLevel.ReadCommitted },
                TransactionScopeAsyncFlowOption.Enabled))
            {
                using (var db = new StarGateDBEntities())
                {
                    var list = await db.TableA.ToListAsync();

                    foreach (var item in list)
                    {
                        item.B = "GG";
                    }

                    // 更新
                    await db.SaveChangesAsync();

                    Console.WriteLine("Transaction 1 saved but wait for commit");

                    // 10 秒後再 commit
                    await Task.Delay(new TimeSpan(0, 0, 10));

                    ts.Complete();

                    Console.WriteLine("Transaction 1 commit");
                }
            }
        }

        private static async Task SecondTransaction()
        {
            using (var ts = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions()
                // 設定 level
                { IsolationLevel = IsolationLevel.ReadCommitted },
                TransactionScopeAsyncFlowOption.Enabled))
            {
                using (var db = new StarGateDBEntities())
                {
                    Console.WriteLine("Transaction 2 querying");

                    var list = await db.TableA.ToListAsync();

                    Console.WriteLine("Transaction 2 queried");
                }
            }
        }

你會看到 FirstTransaction 已經更新資料等著 commit,而在這等待的時間 SecondTransaction 也卡在讀資料,因為他再等 FirstTransaction 完成

終於 FirstTransaction commit,馬上 SecondTransaction 也把資料讀回來了,當然這資料是被更新過的