--------------------------------------锁的分类:

(1)读锁:即共享锁(S)

(2)写锁:即排他锁(X)

S锁可以与S锁兼容,不可与X锁兼容。

X锁与S锁和X锁都不可以兼容。

举例:

一条记录加了共享锁(S),那么其他事务也可以对该条记录加共享锁(S); 但是不能加排他锁,需要等到该共享锁释放之后再加排他锁。

一条记录加了排他锁(S), 那么其他事务即不可以对该条数据加共享锁(S),也不可以加排他锁(X),需要等到该排他锁释放之后再加其他锁。

----------------------------------------锁的对象:

DB2支持对表空间、表、行和索引加锁, 行锁是DB2默认的锁对象。

不过在考虑用户应用程序的并发性的问题上,通常并不检查用于表空间和索引的锁。该类问题分析的焦点在于表锁和行锁。

---------------------------------------锁的模式:

(1)表锁模式:

强类型锁:适用于表中的所有的行,包括:S, U, X, Z

弱类型锁:又叫意向锁(intent),目的是配合行锁,在获得行锁之前必须先获得表锁,包括:IN, IS, IX, SIX

默认情况下,DB2不会实施强类型表锁,只有通过lock table锁表或放生锁升级的时候才会在表上加强类型的锁。

I: intent

N: none

S: share

X: eXclusive

U: update

Z: super eXclusive

弱类型锁模式:

IN

IS

IX

SIX

IS、IX、SIX方式用于表一级并需要行锁配合,他们可以阻止其他应用程序对该表加上排它锁。

IN锁用于表上以允许未提交读这一概念。(UR)

如果一个应用程序获得某表的IS锁,该应用程序可获得某一行上的S锁,用于只读操作,同时其他应用程序也可以读取该行,或是对表中的其他行进行更改。

如果一个应用程序获得某表的IX锁,该应用程序可获得某一行上的X锁,用于更改操作,同时其他应用程序可以读取或更改表中的其他行。

如果一个应用程序获得某表的SIX锁,该应用程序可以获得某一行上的X锁,用于更改操作,同时其他应用程序只能对表中其他行进行只读操作。

强类型锁模式:

S

U

X

Z

S、U、X和Z方式用于表一级,但并不需要行锁配合,是比较严格的表加锁策略。

如果一个应用程序得到某表的S锁。该应用程序可以读表中的任何数据。同时它允许其他应用程序获得该表上的只读请求锁。如果有应用程序需要更改读该表上的数据,必须等S锁被释放。

如果一个应用程序得到某表的U锁,该应用程序可以读表中的任何数据,并最终可以通过获得表上的X锁来得到对表中任何数据的修改权。其他应用程序只能读取该表 中的数据。U锁与S锁的区别主要在于更改的意图上。U锁的设计主要是为了避免两个应用程序在拥有S锁的情况下同时申请X锁而造成死锁的。

如果一个应用程序得到某表上的X锁,该应用程序可以读或修改表中的任何数据。其他应用程序不能对该表进行读或者更改操作。

如果一个应用程序得到某表上的Z锁,该应用程序可以读或修改表中的任何数据。其他应用程序,包括未提交读程序都不能对该表进行读或者更改操作。

notes:U锁一般用于select....for update.. 如: select * from test for update with ur

U锁是介于S和X锁之前的一种锁,目的是在对一个表可读的同时,其他app可以对其可写。(相当于使读锁和写锁可兼容)

(2)行锁模式:

S

U

X

W

NS

NX

NW

---------------------------------------DB2的隔离级别:

UR: uncommited read  不加锁

CS: cursor stability 加一行锁,在当前读到的行加S锁。

RS: read stability   在查询结果加S锁

RR: repeatable stability  读过的行都加S锁。

举例:

表staff中共有10000条数据,如下A事务执行的sql的查询结果中有10条数据:

select * from staff where name='Allen';      --10条

在该sql提交之前,B事务来更改该表的数据。

(1)A事务在查询的时候不加任何锁,则可以读到B事务未提交的数据。                                          ---UR

(2)在10条结果中的一条,即当前条数据加上读锁。B事务不可以更改当前条,但可以更改结果集中的其他条数据。     ---CS

(3)在所有10条结果集上都加读锁。B事务不能更改这10条结果集的数据,但是可以更改不满足sql条件的其他行数据。  ---RS

(4)将A事务读到的所有的行, 即全表,都加读锁。这样B事务就无法更改数据了。                                ---RR

说明:

隔离级别只适用于读,查询的时候通知DB2管理器,决定: 不加锁/加一行锁/对结果集加锁/读过的行都加锁。

对于写操作(增删改),都需要加写锁,即排他锁(X)。

============================================================================================锁等待(lock wait)

------------------------------通过系统表,查看某个表的锁等(lock wait)

1.看某个表被什么用户/进程调用:

db2 "select * from SYSIBMADM.LOCKWAITS"|grep OPP_DETAIL_HISTORY_FACTS

找到用户:AUTHID,进程ID:AGENT_ID

此处AGENT_ID和db2 list applications中Status为"Lock-wait"的Appl一致。

2. select * from  sysibmadm.snaplock;

notes: 即使有所等待的时候,SYSIBMADM.LOCKWAITS / sysibmadm.snaplock系统表里可能也会没有想过锁信息或者表的信息,因为对该表的操作可能只锁了系统表(如SYSTABLES)

------------------------------几种常见的查看锁等待(lock-wait)的方法:

------------------方法1:

找出锁等的sql语句:

监控锁等(wait locks):

db2pd -d <db_name> -locks showlocks wait -tra -app -dyn

db2pd -d sample -locks showlocks wait -tra -app -dyn -file sample_lock_wait.txt

查找步骤:

打开输出文件sample_lock_wait.txt

1.在lock模块中:

Sts为W(wait),是所等待的进程

Sts为G(Granted),表示锁被成功得到,即获得锁的进程

找到他们的TranHdl的值

2.    Transactions模块

根据事务手柄TranHdl的值得到应用手柄AppHandl的值

3.    Applications模块

根据AppHandl的值得到sql唯一标示代码AnchID/ StmtUID (C-AnchID C-StmtUID  L-AnchID L-StmtUID中C: current,当前执行的sql语句, L: last上一句执行的语句)

4.    Dynamic SQL Statements模块

根据sql唯一标示代码AnchID/StmtUID得到sql语句, NumExe表示执行次数

notes:showlocks 可选项

-----------------方法2:

1.db2pd -wlocks -db sample

得到Sts为G的即是lock holder, 为W的为waiter。找出他们对应的AppHandl(如37661,37662)

2.db2pd -apinfo 37661 -db sample

  db2pd -apinfo 37662 -db sample

  或者用:db2 get snapshot for application agentid 37661/37662

----------------方法3:

1.db2top -d samples -i 6

2.按U进入locks,锁请求者的进程Application Status的状态为lock wait

3.按大写L,进入lock chain,查看锁等的等待被等待信息. 110-->112, 则110为lock holder,112为lock requester。

-------------------------------找出锁等超过2分钟的表:

db2 "select rtrim(APPL_NAME),rtrim(AUTHID),rtrim(AGENT_ID),rtrim(TABSCHEMA)||'.'||rtrim(TABNAME) TAB_NAME, minute(current_timestamp-timestamp(LOCK_WAIT_START_TIME)) duration from SYSIBMADM.LOCKWAITS  where minute(current_timestamp-timestamp(LOCK_WAIT_START_TIME))>2"

==============================================================================================================================死锁(dead-lock):

----------------------------------------------------------------------查找死锁(dead-lock):

可以通过事件监控器来查找死锁:

db2 "create event monitor dlockevm for deadlocks with details history write to file '/home/db2inst1/deadlock' "  --DB2 9.7之前

db2 "create event monitor lockevmon for locking write to unformatted event table (table locks)"    --DB2 9.7及之后

然后通过db2evmon工具可以获得死锁信息的日志:

db2evmon –path /home/db2inst1/deadlock > deadlock.txt

分析输出文件deadlock.txt

------------------------------查看锁表:

方法一:

db2 "SELECT * FROM TABLE( SNAPSHOT_LOCK( 'sample', -1 )) as SNAPSHOT_LOCK"| grep OPP_DETAIL_WEEKLY_MQT

db2 "SELECT * FROM TABLE( SNAPSHOT_LOCK( 'sample', -1 )) as SNAPSHOT_LOCK"|

方法二:

db2top -d sample -i 20  

按U监控locks

找出第一列 Agent Id(State)

db2 get snapshot for application agentid 13373

按L可以显示lock chain

方法三:

db2pd -db sample -locks showlock wait

会得到类似: ....Rows(行锁)/X(排他锁) .....TbspaceID 3 TableID 12.... 或者 ...(obj={2;2828})

然后  db2 "select tbspace,tabschema,tabname,tableid,tbspaceid from syscat.tables where tbspaceid=3 and tableid=12"

或者  db2 "select tbspace,tabschema,tabname,tableid,tbspaceid from syscat.tables where tbspaceid=2 and tableid=2828"

方法四:

db2 get snapshot for locks on sample

找到Application handle(如: 29207)

db2 get snapshot for locks for application agentid 29207

方法五:

Select substr(tabschema,1,8) as tabschema, substr(tabname,1,15) as tabname,lock_object_type,
          lock_mode, lock_mode_requested, agent_id_holding_lk
From sysibmadm.lockwaits

方法四的说明:

-------------------------------查看总体锁信息:

db2 get snapshot for database on sample|more
.........
Number of Threshold Violations             = 0
Locks held currently                       = 0                                                                                当前锁的数量
Lock waits                                 = 27                                                                                锁等个数
Time database waited on locks (ms)         = 795431                                                                        表示花费在锁等时间上的总和(除以Lock waits即可算出每个锁等的平均时间)
Lock list memory in use (Bytes)            = 5952                                                                            当前使用的锁内存大小
Deadlocks detected                         = 0                                                                                死锁个数
Lock escalations                           = 0                                                                                锁升级个数
Exclusive lock escalations                 = 0                                                                                排他锁升级个数
Agents currently waiting on locks          = 0                                                                                表示当前正在等待锁的应用数
Lock Timeouts                              = 1                                                                                锁超时个数
Number of indoubt transactions             = 0
..............

......

------------------------------------只看锁(多个时间段)

db2 get snapshot for locks on sb1dm|more
Application handle                         = 38321
Application ID                             = *LOCAL.DB2.150421201313
Sequence number                            = 00001
Application name                           = db2wlmd
CONNECT Authorization ID                   = DB2EIW01
Application status                         = Connect Completed
Status change time                         = 04/21/2015 16:13:09.375760
Application code page                      = 1208
Locks held                                 = 0
Total wait time (ms)                       = 0

------------------------------也可以写成存储过程,可以利用存储过程来判断是否有死锁:

1.

 db2 "CALL OMATIC.LOCK_APP_HOLD('EDGEDM.OPP_DETAIL_HISTORY_FACTS',?)"

 如:

Value of output parameters
  --------------------------
  Parameter Name  : O_APP_HANDLE
  Parameter Value :
  Return Status = 0

 说明:  Parameter Value :后面没有值说明没有lock

 

2.

db2 -x "CALL OMATIC.LOCK_INFO('EDGEDM.OPP_DETAIL_HISTORY_FACTS')" | grep user | sed 's/[ t]*$//g'

---------------------------------------------------------监控锁(等)参考同文件夹下word:查找锁等_例子.docx

db2pd –d <db_name> -locks wait –tra –app –dyn
db2pd -d sb1dm -locks wait -tra -app -dyn > lock_sb1dm.inf
db2pd -d sb1dm -locks showlocks wait -tra -app -dyn > lock_det_sb1dm.inf

这样可以查出表的具体sql

=============================================================================================================================手工上锁,死锁:

db2 lock table tablename in exclusive mode
db2 lock table tablename in share mode
db2 +c lock table tablename in exclusive mode

=============================================================================================================================锁超时:

如果锁持有者一直不提交,锁的请求者不能一直等下去,这就需要设置一个锁超时时间,LOCKTIMEOUT,若为-1则表示一直等下去,交易系统建议设置时间短一些(30--60s),仓库系统可以长一些。

-----------------------------------------锁超时时间:

db2 get db cfg|grep -i lock  
.........
Lock timeout (sec)                        (LOCKTIMEOUT) = 600
............

修改锁超时时间:

db2 update db cfg for LOCKTIMEOUT using 60

=============================================================================================================================锁升级:

锁升级就是由行锁转换为表锁,从而减少锁的数量,释放内存资源的过程。 (因为所是一种内存资源,每个锁都需要占用一定的内存空间)

锁升级通过两个数据库参数locklist和maxlocks触发锁升级。locklist控制每个数据库可以使用的最大锁内存大小。maxlocks用来控制每个应用程序占用锁内存的百分比。

锁升级发生的条件:

1. 内存使用超过了locklist的大小。

2. 某个应用程序的锁的内存空间达到了locklist*maxlocks%

查找锁升级:

db2 get snapshot for database on sample

关键字:

Exclusive lock escalations                 = 0                                                                                排他锁升级个数

锁升级在诊断日志中会有记载,可以通过关键字escalation查找。

======================================================================================================锁转换:

锁转换是锁的模式的转换,是从弱类型的锁转换为强类型的过程,如S-->X, 使用场景如:一个事务读取某行数据,加了S锁,但是此时该事务需要更新此行,则需要获取X锁,S锁就转换为X锁。

-------------------------------------------表锁模式/锁类型:

弱类型锁:

IN     意向无(Intent None)

IS     意向共享锁(Intent Share)

IX     意向排他锁(Intent eXclusive)

SIX    (Share with Intent eXclusive)

强类型锁:

S     共享锁(Share)

U     更新锁(Update)

X     排他锁(eXclusive)

Z     超级排他锁(Super eXclusive)

notes: 强类型锁适用于表中的所有的行,属于行锁

       弱类型锁又叫意向锁,目的是为了配合行锁,在获得行锁之前先获得表锁,(属于表锁)。

       

-------------------------------------------------DB2锁的重要特性:已落实机制(Currently Committed, CC)

dst33lp14:/home/devdba$ db2 get db cfg for sample|grep -i cur_commit

 Currently Committed                        (CUR_COMMIT) = ON

如果某个事务查询时,另外一个事务正在做增删改操作,那么查询事务需要等待增删改操作完成提交并且释放锁,才能查询。

Currently Committed是CS隔离级别的新实现(只针对默认的CS隔离级别),如果开启Currently Committed机制,则无需等待,会从日志中获取已落实版本的数据,即isnert,update,delete之前的数据,

无需等待。

修改CC参数:

db2 update db cfg for sample using CUR_COMMIT OFF
db2 update db cfg for sample using CUR_COMMIT ON

默认情况下CC参数是开启的。

------------------------------手工上锁,死锁:

db2 lock table tablename in exclusive mode
db2 lock table tablename in share mode
db2 +c lock table tablename in exclusive mode

db2 +c表示不自动提交。可以再执行commit提交或者rollback回滚。

-----------------------------创建一个锁等lock wait:

在一个窗口:

db2 +c "create table TEST.TEST_LK (i1 integer)"

在另一个窗口:

db2 "select * from TEST.TEST_LK"

---通过db2pd找出lock wait:

第三个窗口:

db2pd -database sample -locks -transactions -agents -file sample_lock2.txt
50684 -->50685
50684->51187  
50684 51187
51187->51188
51187 51188