程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> DB2鎖問題分析與解釋

DB2鎖問題分析與解釋

編輯:DB2教程

DB2鎖問題分析與解釋


DB2 鎖問題分析與解釋


DB2 應用中經常會遇到鎖超時與死鎖現象,那麼這種現象產生的原因是什麼呢。本文以試驗的形式模擬鎖等待、鎖超時、死鎖現象,並給出這些現象的根本原因。


試驗環境:


DB2 v9.7.0.6
AIX 6.1.0.0
采用默認的隔離級別CS

STUDENT表的DDL與初始內容
------------------------------------------------
-- DDL Statements for table "E97Q6C "."STUDENT"
------------------------------------------------

CREATE TABLE "E97Q6C "."STUDENT" (
"AGE" INTEGER ,
"NAME" CHAR(8) )
IN "USERSPACE1" ;


$ db2 "select * from student"


AGE NAME
----------- --------
3 xu
5 gao
2 liu
1 gu







試驗1:驗證insert操作與其他操作的鎖等待問題


session 1中發出insert操作,在session 2中觀察insert,update,delete操作是否會鎖超時。


session 1
---------
$ db2 +c "insert into student values(4, 'miao')"
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I The SQL command completed successfully.
$ db2 "update student set name='gu' where age=1"
DB20000I The SQL command completed successfully.
$ db2 "delete from student where age=2"
DB20000I The SQL command completed successfully.

----------------------------------------------------------------------------

結論1:當session 1對表作insert操作時,session 2對該表的insert及其他行的update,delete操作都不會有問題


----------------------------------------------------------------------------


試驗2:驗證update操作與其他操作的鎖等待問題
session 1中發出update操作,在session 2中觀察insert,update,delete操作是否會鎖超時。
--------------
session 1
---------
$ db2 commit


$ db2 "select * from student"


AGE NAME
----------- --------
3 xu
5 gao
6 mu
4 miao
1 gu


5 record(s) selected.


$ db2 +c "update student set name = 'qing' where age=4"
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I The SQL command completed successfully.
$ db2 "update student set name='gu' where age=1"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "68". SQLSTATE=40001
$ db2 "delete from student where age=2"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "68". SQLSTATE=40001


----------------------------------------------------------------------------
結論2:當session 1對表某一行做update操作時,session 2可以對該表作insert操作,但不允許對其他行的delete和update操作
----------------------------------------------------------------------------

試驗3:驗證delete操作與其他操作的鎖等待問題
session 1中發出delete操作,在session 2中觀察insert,update,delete操作是否會鎖超時。

Session 1
---------
$ db2 commit


$ db2 +c "delete from student where age=4"
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 "insert into student values(6, 'mu')"
DB20000I The SQL command completed successfully.


$ db2 "update student set name='gu' where age=1"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "68". SQLSTATE=40001


$ db2 "delete from student where age=2"
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "68". SQLSTATE=40001
----------------------------------------------------------------------------
結論3:當應用1對表某一行做delete操作時,應用2可以對該表作insert操作,但不允許對其他行的delete和update操作
----------------------------------------------------------------------------


總的結論是:
應用對表作insert操作時,其他操作不受影響,也不受其他操作影響。
作update,delete操作時,其他的update和delete操作受影響。


為了解釋以上現象的原因,我們首先看一下上面的操作需要什麼樣的鎖。


session 1.
---------
$ db2 rollback


$ db2 +c "insert into student values(7,'han')"
DB20000I The SQL command completed successfully.


$ db2pd -db qsmiao -locks

\


結論:insert操作需要表級的IX鎖和行級的X鎖。
注:IX鎖,該鎖的擁有者在擁有相應行的X鎖時可以更改該行的數據。


$ db2 rollback


$ db2 +c "update student set name='yan' where age=5"
DB20000I The SQL command completed successfully.


$ db2pd -db qsmiao -locks

\


結論:update操作需要表級的IX鎖和行級的X鎖。


$ db2 rollback


$ db2 +c "delete from student where age=6"

DB20000I The SQL command completed successfully.

$ db2pd -db qsmiao -locks

\



結論:update操作需要表級的IX鎖和對應的行級的X鎖(這裡因為3條記錄的age都為6,因此需要3個行級鎖)。


現在的問題是:為什麼insert和update,delete操作需要的鎖一樣(表級的IX鎖,對應行級的X鎖),但是表現的效果卻不一樣呢?


為了解決這個問題,看一下他們的執行計劃吧:


$ db2expln -d qsmiao -g -statement "insert into student values(5, 'gao')" -terminal

\

$ db2expln -d qsmiao -g -statement "update student set name='qing' where age=4" -terminal

\



$ db2expln -d qsmiao -g -statement "delete from student where age=6" -terminal

\


從上面的執行計劃中可以看到原因:insert操作不需要表掃描,而update和delete操作都需要全表掃描,而且會在掃描的時候試圖對每一行加U鎖。
導致鎖超時的原因就是表掃描
例如session 1要更新表的某一行,會在該行加上X鎖。之後, session 2試圖更新該表的另一行,進行全表掃描時,就會試圖對A占用的那一行加上U鎖,但無能為力,最終導

致鎖超時。

為了驗證該說法,可以抓取鎖等待的消息,


session 1
---------
$ db2 +c "update student set name='hehe' where age = 4"
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 +c "delete from student where age=6"
<-------這時會hang住,因為它在等session 1的鎖


session 3
---------
$ db2pd -db qsmiao -wlocks <---在鎖超時發生之前,抓取鎖等待的消息

Locks being waited on :
AppHandl [nod-index] TranHdl Lockname Type Mode Conv Sts CoorEDU AppName AuthID AppID
15393 [000-15393] 2 00020004000000000000000952 Row ..X G 7818 db2bp E97Q6C *LOCAL.e97q6c.141016035113
15408 [000-15408] 16 00020004000000000000000952 Row ..U W 10153 db2bp E97Q6C *LOCAL.e97q6c.141016035219


可以看到,是因為U鎖和X鎖的不兼容導致鎖等待,最後導致鎖超時。



為了解決該鎖等待問題,可以在查詢謂詞所涉及的列age上建立索引,避免全表掃描


試驗4:通過建立索引,消除鎖等待現象


session 1
---------
$ db2 rollback


$ db2 +c "lock table student in share mode"


$ db2 +c "create index stu_idx on student(age)"


$ db2 commit


$ db2 +c "update student set name='hehe' where age = 4"
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 +c "delete from student where age=6" <--沒有發生鎖等待現象,直接成功
DB20000I The SQL command completed successfully.


可以看到,已經通過索引解決了該鎖超時問題,如果讀者有興趣的話,可以看下建立索引之後的訪問計劃。






下面模擬一個死鎖現象
試驗5:模擬死鎖,過程如下
第一步:session 1 獲得 鎖 LOCK1


第二步:session 2 獲得 鎖 LOCK2


第三步:session 2 申請 鎖 LOCK1


第四步:session 1 申請 鎖 LOCK2


為了避免死鎖之前產生鎖超時,先將鎖超時控制參數設為-1(表示永遠等待)
update db cfg using locktimeout -1
之後重啟數據庫


session 1
---------
$ db2 +c "update student set name = 'an' where age = 1" <--獲得鎖LOCK1,成功
DB20000I The SQL command completed successfully.


session 2
---------
$ db2 +c "update student set name = 'two' where age = 4" <--獲得鎖LOCK2,成功
DB20000I The SQL command completed successfully.


$ db2 +c "update student set name = 'four' where age = 1" <--申請鎖LOCK1,hang住,因為LOCK1被session 1持有


session 1
---------
$ db2 +c "update student set name = 'three' where age = 4" <--申請鎖LOCK2,hang住,因為LOCK2被session 2持有




這時已經發生了死鎖,10s之後,這兩個session有一個會報出如下死鎖(reason code 2)錯誤,另一個session成功執行
SQL0911N The current transaction has been rolled back because of a deadlock
or timeout. Reason code "2". SQLSTATE=40001


參考資料:
標准表的鎖定方式和存取方案,這裡您可以看到詳細的加鎖方式
http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.admin.perf.doc/doc/r0005275.html?lang=zh


附,只能在發生死鎖或者鎖等待的時候才能用db2pd查看鎖的信息。下面附上如何采用事件監控器監控死鎖/鎖超時。事件監控器可以抓取一段時間內的鎖事件
db2 update db cfg for sample using MON_LOCKWAIT hist_and_values MON_DEADLOCK hist_and_values MON_LOCKTIMEOUT hist_and_values MON_LW_THRESH 10000
db2 "CREATE EVENT MONITOR LOCKEVMON FOR LOCKING WRITE TO UNFORMATTED EVENT TABLE (TABLE LOCKEVMON)"
db2 set event monitor LOCKEVMON state=1


重現問題


db2 flush event monitor LOCKEVMON
db2 set event monitor LOCKEVMON state=0


cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/db2evmonfmt.java ./
cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/DB2EvmonLocking.xsl ./
export PATH=/home/db2users/e97q6c/sqllib/java/jdk64/bin:$PATH


javac db2evmonfmt.java


java db2evmonfmt -d qsmiao -ue LOCKEVMON -ftext -u e97q6c -p e97q6c > deadlock.txt
more deadlock.txt 可以看到有關的SQL語句。




請參考
http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-1004lockeventmonitor/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved