1. 程式人生 > >DB2中幾個隔離級別select..for update with ** 的行鎖

DB2中幾個隔離級別select..for update with ** 的行鎖

最近專案中遇到了多執行緒高併發專案db2資料庫表死鎖的情況,蒐集了一些關於表死鎖的資料

Create table RRTest (pkID VARCHAR(20) NOT NULL ,unID1 varchar(20) Not NULL,UnID2 varchar(20) ,"CUSTOMER_ID"VARCHAR(6) ,
                  "ORDER_TYPE"

 DECIMAL(2,0) , 
                  "EXECUTION_TYPE" DECIMAL(2,0) , 
                  "ORDER_DATE"
 VARCHAR(8) , 
                  "ORDER_TIME" VARCHAR(6) , 
                  "ORDER_DATETIME"
 TIMESTAMP , 
                  "SIDE" DECIMAL(1,0) , 
                  "TRADE_TYPE" DECIMAL(1,0) , 
                  "ORDER_AMOUNT" DECIMAL(15,2) , 
                  "ORDER_PRICE" DECIMAL(8,4),
                   TSID varchar(20) ) 

insert into RRTest 
SELECT Order_ID, Order_ID, Order_ID, CUSTOMER_ID, ORDER_TYPE, EXECUTION_TYPE, ORDER_DATE, ORDER_TIME,ORDER_DATETIME, SIDE, TRADE_TYPE, ORDER_AMOUNT, ORDER_PRICE ,ORDER_ID
    FROM DB2INST1.Fx_Order where ORDER_DATE >'20070401'
GO
select count(*) From RRTEST
72239

ALTER TABLE "DB2INST1".RRTest
        ADD PRIMARY KEY
                (pkID);

CREATE UNIQUE INDEX UNIQINDX ON RRTest(unID1)
CREATE INDEX INDX002 ON RRTest(unID2)
db2 "RUNSTATS ON TABLE DB2INST1.RRTest ON ALL COLUMNS AND INDEXES ALL ALLOW WRITE ACCESS"
 

db2 connect to db2TT
db2 +c

select * From RRTEST where TSID='20070223ORD01267732' for update with RR
select * From RRTEST where TSID='20070222ORD01266302' for update with RR

select * From RRTEST where TSID='20070223ORD01267732' for update with RS
select * From RRTEST where TSID='20070222ORD01266302' for update with RS
 
select * From RRTEST where unID1='20070223ORD01267732' for update with RR
select * From RRTEST where unID1='20070222ORD01266302' for update with RR
select * From RRTEST where unID1='20070223ORD01267732' for update with RS
select * From RRTEST where unID1='20070222ORD01266302' for update with RS
 
select * From RRTEST where unID2='20070223ORD01267732' for update with RR
select * From RRTEST where unID2='20070222ORD01266302' for update with RR
select * From RRTEST where unID2='20070223ORD01267732' for update with RS
select * From RRTEST where unID2='20070222ORD01266302' for update with RS
 
select * From RRTEST where pkID='20070223ORD01267732' for update with RR
select * From RRTEST where pkID='20070222ORD01266302' for update with RR
select * From RRTEST where pkID='20070223ORD01267732' for update with RS
select * From RRTEST where pkID='20070222ORD01266302' for update with RS
 

按照以上欄位 pkID 是主鍵,unID1 是唯一健索引,unID2 是普通健索引,TSID 是普通欄位,沒有在上建立索引。

試驗結論:

 

     

 PK_INDEX    UNIQ_INDEX   NormalINDEX   NO_INDEX
 WITH RR 鎖行,不鎖表  鎖行,不鎖表  不鎖行,不鎖表(1)  鎖行,鎖表
 WITH RS

鎖行,不鎖表

 鎖行,不鎖表  鎖行,不鎖表  鎖行,鎖表(2)
         

 

鎖行是指在一個事務中用某種方式讀取並更改了改行資料並顯示得指明要修改後,這個事務將鎖住改行,直到它提交或者回滾了事務後,才釋放該鎖。

鎖表是指在用以上各種SQL在讀取並更改一行的同時鎖住了整個表。

對以上紅字部分(1)可能有不能理解的是:為什麼對普通索引和主鍵或者唯一健索引的不同結論? 

 對 PK和UNIQ的解釋是因為RR 是可重複的讀的級別,對這次檢索掃描到的有可能成為自己的潛在檢索物件的內容都會鎖住,而因為是主鍵或者唯一健,別的行不可能成為這次這個檢索的潛在讀的範圍,就是對別的資料此事務根本就沒有必要鎖,任何情況的更改都不可能出現幻讀的情況(此表上的約束限制),所以只鎖這一行。這麼理解對PK,UNIQ沒有問題。

但是NormalINDEX 我認為應該是鎖住這個表而不是不鎖。這點一直沒想明白。留待以後再加強理解。

對 RS隔離級別是“鎖定檢索到的資料行”,是通過SQL檢索到的結果進行鎖定, PK,UNIQ,INDEX的結論完全都可以理解。 對 tableScan的檢索而出現的鎖表有些象RR隔離級別的所為。

嗯,想了一圈沒想明白,故把詳細過程貼出來給自己留個紀念,以供以後遇到此類併發控制程式中注意一下,select * From TTT where ****= ? for update with RR(RS),這裡的 *** 可不是隨便定義的。

隔離級別分為RR/RS/CS/UR這四個級別。 下面讓我們來逐一論述:

1. RR隔離級別: 在此隔離級別下, DB2會鎖住所有相關的紀錄。 在一個SQL語句執行期間, 所有執行此語句掃描過的紀錄都會被加上相應的鎖。 具體的鎖的型別還是由操作的型別來決定, 如果是讀取,則加共享鎖; 如果是更新, 則加獨佔鎖。 由於會鎖定所有為獲得SQL語句的結果而掃描的紀錄, 所以鎖的數量可能會很龐大, 這個時候, 索引的增加可能會對SQL語句的執行有很大的影響,因為索引會影響SQL語句掃描的紀錄數量。

2. RS隔離級別: 此隔離級別的要求比RR隔離級別稍弱,此隔離級別下會鎖定所有符合條件的紀錄。 不論是讀取, 還是更新, 如果SQL語句中包含查詢條件, 則會對所有符合條件的紀錄加相應的鎖。 如果沒有條件語句, 也就是對錶中的所有記錄進行處理,則會對所有的紀錄加鎖。

3. CS隔離級別: 此隔離級別僅鎖住當前處理的紀錄。

4. UR隔離級別:此隔離級別下,如果是讀取操作,不會出現任何的行級鎖。對於非只讀的操作,它的鎖處理和CS相同。

 

DB2預設的隔離級別是 CS。即 遊標穩定性。