最近项目中遇到了多线程高并发项目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
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。即 游标稳定性。