[筆記]TranscationScope造成的Table Lock現象

  • 9995
  • 0

摘要:[筆記]TranscationScope造成的Table Lock現象

ASP.NET 2.0以來有一個機制方便我們包裝Transaction=>TransactionScope 類別

黑暗大很久以前也有介紹過=>KB-.NET 2.0 分散式交易新利器---TransactionScope

平常沒用到,等到用到在查看才發現到一些現象=>這些現象黑暗大就有提到了,我只是精簡幫自己做一個筆記。

精簡後的程式碼=>

            TransactionOptions options = new TransactionOptions();
            options.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead;
            options.Timeout = new TimeSpan(0, 2, 0);

            TransactionOptions options = new TransactionOptions();
            options.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead;
            options.Timeout = new TimeSpan(0, 2, 0);

using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required, options))
            {
                using (SqlConnection conn1 = new SqlConnection("Server=xxx;Database=xxx;uid=sa;pwd=xxx;"))

                {
                    try
                    {
                        conn1.Open();

                        string cmdText = @"INSERT INTO T1 (C1,C2) VALUES ('1','1000')";

                        SqlCommand cmd1 = new SqlCommand(cmdText, conn1);
                        cmd1.ExecuteNonQuery();

                        string cmdText2 = @"UPDATE T2 SET C2 = '123456' FROM T2 WHERE C1 = '3'";

                        SqlCommand cmd2 = new SqlCommand(cmdText2, conn1);
                        cmd2.ExecuteNonQuery();


                    }

                    catch (Exception ex)
                    {
                        throw ex;
                    }

                }
SELECT * FROM T1
SELECT * FROM T2

原始資料

處理完

 

 

當我們開始執行時,可以中斷在ExecuteNonQuery
斷在第一段Insert會發現T1被Lock了,T2沒被Lock
再往下跑到Update的ExecuteNonQuery
會發現T1,T2都被Lock了
這是用

SELECT * FROM T1
SELECT * FROM T2

的結果。如同黑暗大說的,是以Table Lock的方式。

然而,以前會被前輩教導,select table都要加上with nolock
因此

SELECT * FROM T1 WITH (NOLOCK)
SELECT * FROM T2 WITH (NOLOCK)

但是萬一還沒commit前你就這樣抓到資料了,
程式有問題rollback了,這兩筆資料就不對了,
雖然說這時間很短,我沒中斷的話也感覺不出有Table Lock,
但是交易系統幾萬筆資料在跑,你難保不會那一天出這個問題,
到時要追就追不到。
所以需要的是抓到已經commit的資料來處理
這時就可以用

 

SELECT * FROM T1 WITH (READPAST)
SELECT * FROM T2 WITH (READPAST)



這樣就可以抓到沒有被影響到的筆數來處理

接下來,我們來看Table Lock的範圍,其實他並不是整個Table都不能存取的,

                        string cmdText = @"INSERT INTO T1 (C1,C2) VALUES ('2','2000')";

                        SqlCommand cmd1 = new SqlCommand(cmdText, conn1);
                        cmd1.ExecuteNonQuery();

                        string cmdText2 = @"UPDATE T2 SET C2 = '123456' FROM T2 WHERE C1 = '1'";

                        SqlCommand cmd2 = new SqlCommand(cmdText2, conn1);
                        cmd2.ExecuteNonQuery();

一樣中斷在第二段指令

SELECT * FROM T1
SELECT * FROM T2

依然是Lock的狀態
 

select * from t1 where c1 = '1'
select * from t2 where c1 = '2'

這段Query依然也是Lock的狀態,
此時我把T1,T2的C1攔位都加上PK,
再來下這段Query



我們就可以針對該筆去存取了
所以我們可以看到有PK的Table就可以做到是Record Lock
但是萬一你下的where條件沒有在PK,或是包含Lock那一筆資料,還是會Lock的。