准備工作
db2命令行下,執行:list command options,如圖:
注意,Auto Commit缺省是ON,即自動提交。使用下面的命令來查看設置:
執行命令:
update command options using c off,
再執行命令:list command options,如圖:
這時可以看到Auto Commit 已經變為OFF了
DB2使用一個叫做“CURRENT ISOLATION”的special register來記錄session的隔離級別。查看當前隔離級別有兩種方法:
VALUES CURRENT ISOLATION
或
SELECT CURRENT ISOLATION FROM SYSIBM.SYSDUMMY1
設置隔離級別命令如下(此命令不需要顯式COMMIT):
SET CURRENT ISOLATION TO UR/CS/RS/RR
由於該測試需要並發事務,所以我們要用同樣方法,再打開一個窗口。以下稱為session1和session2。
把兩個session都連接到DINGTEST數據庫,並建一張表TA如下:
AC1 AC2
1 1
2 2
3 3
4 4
5 5
至此准備工作完成,我們開始實驗。
注:每次實驗完以後別忘記清理環境,即把session commit/rollback。
實驗1
測試在“UR”隔離級別下是否會產生“丟失更新”的問題。
方法:兩個session並發更新同一條記錄。
STEP 0:把session1和session2都設置為UR隔離級別:
SET CURRENT ISOLATION TO UR
STEP 1:在session1中做更新操作,但不提交:
UPDATE TA SET AC2 = 2 WHERE AC1 = 1
STEP 2:在session2中對同一條記錄做更新操作:
UPDATE TA SET AC2 = 3 WHERE AC1 = 1
Session2被block住……
STEP 3:在session1中做commit/rollback操作,則session2會立刻繼續執行。
結論:在“UR”隔離級別下不會產生“丟失更新”的問題。
實驗2
測試在“UR”隔離級別下是否會產生“讀髒數據”的問題。
方法:在session2中查詢session1中更改但未提交的數據。
STEP 0:把兩個session都設置為UR隔離級別:
SET CURRENT ISOLATION TO UR
STEP 1:在session1中做更新操作,但不提交:
UPDATE TA SET AC2 = 4 WHERE AC1 = 1
STEP 2:在session2中查詢該記錄:
SELECT * FROM TA WHERE AC1 = 1
Session2中立即返回查詢結果,該記錄值為session1更新後的值,這實際是一個髒數據,session1有可能最終會rollback。
STEP 3:在session1中做rollback操作。
STEP 4:在session2中再次查詢該記錄。
SELECT * FROM TA WHERE AC1 = 1
該記錄值為session1更新前的值,因為session1已經rollback了,第一次讀到的是一個髒數據。
結論:在“UR”隔離級別下會產生“讀髒數據”的問題
實驗3
測試在“CS”隔離級別下是否會產生“讀髒數據”的問題。
方法:在session2中查詢session1中更改但未提交的數據。
STEP 0:把兩個session都設置為CS隔離級別:
SET CURRENT ISOLATION TO CS
STEP 1:在session1中做更新操作,但不提交:
UPDATE TA SET AC2 = 5 WHERE AC1 = 1
STEP 2:在session2中查詢該記錄:
SELECT * FROM TA WHERE AC1 = 1
Session2被block住……
STEP 3:在session1中做commit/rollback操作,則session2會立刻繼續執行。
結論:在“CS”隔離級別下不會產生“讀髒數據”的問題。
實驗4
測試在“CS”隔離級別下會是否會產生“不可重復讀”的問題。
方法:嘗試在session1的兩次查詢之間修改其查詢的記錄。
STEP 0:把兩個session都設置為CS隔離級別:
SET CURRENT ISOLATION TO CS
STEP 1:在session1中做查詢操作,但不提交:
SELECT * FROM TA WHERE AC1 = 1
假定查詢結果中AC2為“4”。
STEP 2:在session2中更新此記錄,並提交(不提交的話,session1就無法再查詢該記錄了):
UPDATE TA SET AC2 = 5 WHERE AC1 = 1
COMMIT
STEP 3:在session1中再次查詢該記錄:
SELECT * FROM TA WHERE AC1 = 1
這次查詢結果中,AC2為“5”。這就產生了在同一個事務中,兩次查詢的數據不一致的問題。
結論:在“CS”隔離級別下會產生“不可重復讀”的問題
實驗5
測試在“RS”隔離級別下是否會產生“不可重復讀”的問題。
方法:嘗試在session1的兩次查詢之間修改其查詢的記錄。
STEP 0:把兩個session都設置為RS隔離級別:
SET CURRENT ISOLATION TO RS
STEP 1:在session1中做查詢操作,但不提交:
SELECT * FROM TA WHERE AC1 = 1
假定查詢結果中AC2為5
STEP 2:在session2中更新此記錄:
UPDATE TA SET AC2 = 6 WHERE AC1 = 1
Session2被block住……
STEP 3:在session1中再次查詢該記錄:
SELECT * FROM TA WHERE AC1 = 1
這次查詢結果中,AC2仍然為5。這表明在RS隔離級別下,在事務中,查詢的記錄都被lock住了,以保證同一事務中,多次查詢的數據都一致。
STEP 4:在session1中做commit/rollback操作,則session2立即繼續執行。
結論:在“RS”隔離級別下不會產生“不可重復讀”的問題。
實驗6
測試在“RS”隔離級別下是否會產生“幻象記錄”的問題。
方法:嘗試在session1的兩次查詢之間添加符合其查詢條件的記錄。
STEP 0:把兩個session都設置為RS隔離級別:
SET CURRENT ISOLATION TO RS
STEP 1:在session1中做查詢操作,但不提交:
SELECT * FROM TA WHERE AC1 > 0 AND AC1 < 10
假定查詢結果有5條記錄。
STEP 2:在session2中INSERT一條記錄,並提交:
INSERT INTO TA (AC1, AC2) VALUES (6, 1)
COMMIT
STEP 3:在session1中做同樣的查詢操作:
SELECT * FROM TA WHERE AC1 > 0 AND AC1 < 10
這次查詢結果中,變成了6條記錄。這就產生了在同一個事務中,兩次查詢的數據不一致的問題。雖然第一次查到的記錄都被lock住了不會被改變,但若在兩次查詢之間,其它session若新插入了記錄,則在第二次查詢中也會被查到。該記錄被稱為幻象(phantom)記錄。
結論:在“RS”隔離級別下會產生“幻象記錄”的問題
實驗7
測試在“RR”隔離級別下是否會產生“幻象記錄”的問題。
方法:嘗試在session1的兩次查詢之間添加符合其查詢條件的記錄。
STEP 0:把兩個session都設置為RR隔離級別:
SET CURRENT ISOLATION TO RR
STEP 1:在session1中做查詢操作,但不提交:
SELECT * FROM TA WHERE AC1 > 0 AND AC1 < 10
假定查詢結果有6條記錄。
STEP 2:在session2中INSERT一條記錄:
INSERT INTO TA (AC1, AC2) VALUES (7, 1)
Session2被block住了……
STEP 3:在session1中做同樣的查詢操作:
SELECT * FROM TA WHERE AC1 > 0 AND AC1 < 10
查詢結果仍為6條記錄,且數據和第一次查詢保持一致。
STEP 4:在session1中做commit/rollback操作
則session2立即繼續執行。
結論:在“RR”隔離級別下不會產生“幻象記錄”的問題。
作者“java-true”