ORACLE-锁

第01部分-如果没有隔离和锁机制并发读写会相互干扰

本帖最后由 zcs0237 于 2013-6-9 14:09 编辑

 

01.1-未确认的相关性dirty read(脏读|错读)

1、Mary的原工资为2000, 财务人员将Mary的工资改为了8000(但未提交事务)         

2、Mary读取自己的工资 ,发现自己的工资变为了8000,欢天喜地!

3、财务发现操作有误而回滚,Mary的工资还原成2k,Mary读到的数据就是垃圾数据。

01.2-两次结果不一致读nonrepeatable read(不可重复读)

1.在事务1中,Mary 读取了自己的工资为2k,操作并没有完成

2.在事务2中,这时财务人员修改了Mary的工资为3k,并提交了事务.

3.在事务1中,Mary 再次读取自己的工资时,工资变为了3k

01.3-不一致的统计phantom read(幻读|假读)

1.事务1,用where子句读统计目前工资为2k的员工,共10条记录。

2.事务2插入了一条员工记录,这个新行也满足事务1使用的查询where子句工资为2k

3.事务1再次读取所有工资为2k的员工 共读取到了11条记录,这个行被称为幻象,因为对事务1来说,这一行的出现是不可思议的幻像(怀疑看花眼了 )。

01.4-不知对方已更新Lost update(丢失更新|重复更新)

公司给员工张三加1k人民币,财务部两名操作员A和B,操作员A和B只要一前一后做提交,这个过程最后结果是:张三开心了这次涨了2k。过程情况若是这样的:

1、A在应用系统的页面上查询出张三的薪水信息,然后选择薪水记录进行修改,打开修改页面但A突然有事离开了,页面放在那没有做任何的提交。

2、这时候B同样在应用中查询出张三的薪水信息,然后选择薪水记录进行修改,录入增加薪水额1000,然后提交了。

3、这时候A操作员回来了,在自己之前打开的薪水修改页面上增加薪水额1k并提交。

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

 

 

第02部分-用隔离与锁两种控制机制应对并发干扰

本帖最后由 zcs0237 于 2013-6-9 14:22 编辑

 

数据库是要被客户所共享访问的,在数据库操作过程中很可能出现相互干扰、结果不正确的情况。可从两方面采取措施确保每一用户能以一致的方式读取和修改数据:

 

02.1-在客户端实施事务隔离:Read Committed不很好解决不可重读、假读|幻读、丢失更新

 

oracle仅支持SQL92标准中的两个——SERIALIZABLE | READ COMMITTED

oracle又支持两种非标准的——两种事务级事务隔离(Read  WriteRead Only

 

1、两种会话级事务隔离

 

SQL> set transaction isolation level xxx;

ORA-02179: valid options: ISOLATION LEVEL { SERIALIZABLE | READ COMMITTED }

1.png

2、两种事务级事务隔离(Read  Write,同read commited

SQL> set transaction read xxx;

ORA-02178: correct syntax is: SET TRANSACTION READ { ONLY | WRITE }

2.png

 

02.2-在共享数据上加锁可与事务隔离完美结合:使用合适的锁能解决不可重读、假读|幻读、丢失更新

1、行级6号TX排它锁

2、表级2~6号TX锁

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第03部分-实例演示事务的四种隔离功能

本帖最后由 zcs0237 于 2013-6-10 12:03 编辑

 

03.1-set transaction read only(支持repeatable read

一、会话1: 不允许在read only事务中执行DMLSYS除外)

SQL> conn scott/tiger

create table test(id number);

insert into test values(1);

insert into test values(2);

commit;

set transaction read only;

delete from test where id=1;

--ORA-01456: may not perform insert/delete/update operation inside a READ ONLY

Transaction

 

二、会话2: 只能看到事务开始前已提交结果, 看不到其他会话新提交的修改,即transaction-level read consistency,避免了非重复读和幻读

 

SQL> conn scott/tiger

insert into test values(3);

commit;

SQL> select * from test;

--         1

--         2

--         3

会话1:

select * from test;

--   1   //还是只看到两条

--   2

 

03.2-set transaction read writeoracle默认, 基于undostatement-level read consitency

 

一、session 1:创建过程

SQL>  set sqlprompt '_user @session1> ';

drop table t3 purge;

create table t3 (name varchar2(9),cash int);     

insert into t3 values('zcs',10000);

commit;

SYS @session1> set transaction read write;

variable i refcursor;

exec open :i for select * from t3;

 

二、session 2:修改并提交

SQL>  set sqlprompt '_user @session2>';

update t3 set cash=8888 where name='zcs';  

commit;

SYS @session2> select  '-- CASH '||CASH from t3;

-- CASH 8888  //查看到新值

三、session 1:CR

SYS @session1> select distinct status,sum(bytes),count(*) from dba_undo_extents group by status;

 

  UNEXPIRED    1310720          5     //有未过期的undo

  EXPIRED      4849664         29

 

SYS @session1> print i;

zcs            10000      //继续原查询是CR读:过程起始时间的值

SYS @session1> select name,cash from t3;

zcs             8888      //再次查询是当前模式读  

 

03.3-alter session set isolation_level=read commited(默认)

一、session2提交前,session1只能看到原值

Session 1:

SQL> set transaction isolation level read committed;

Session 2:

SQL> update emp set sal=4000 where ename='SCOTT';

Session 1:——只能看到旧值

SQL> select sal from emp where ename='SCOTT';

      3000

二、session2提交后,session1能看到新值

Session 2:

SQL> commit;

Session 1:

SQL> select sal from emp where ename='SCOTT';

      4000

===================================================

做完实验后恢复emp的值默认值:

SQL> update emp set sal=3000 where ename='SCOTT';

commit;

03.4-alter session set isolation_level=serializable(其它会话看不到串行化事务新提交的数据,影响并发性能)

一、session1:(SYS用户不支持此种隔离)

SCOTT @session1> set heading off ;

create table test (id int) ;

alter session set isolation_level=serializable;

insert into test (id) values (1);

select count(*) from test;

         1

二、session2:——无法看到会话1提交的变化

SCOTT @session2> set heading off ;

set sqlprompt '_user @session2> ';

select count(*) from test;

         0

SCOTT @session2> insert into test (id) values(2);

commit;

select count(*) from test;

         1

 

三、session2:——无法看到会话2递交的数据

SCOTT @session1> select count(*) from test;

         1

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第04部分-补充:事务基础知识

本帖最后由 zcs0237 于 2013-6-10 12:38 编辑

 

04.1-transaction的组成

一、执行以下SQL 语句时事务开始

insert、delete、update、merge、select for update、lock table

二、遇到下面事件之一结束

1、commit或rollback被发布

2、DDL 或DCL 语句执行(隐式提交和回滚)

3、用户正常退出SQL*Plus等客户程序

4、异常退出

5、set autocommit on每执行一条语句,就自动提交。

三、commit前可基于保存点rollback或完全rollback

1.png

 

create table t5 (id int, name char(10));

insert into t5 values(1,'AAA');

insert into t5 values(1,'BBB');

insert into t5 values(1,'CCC');

commit;

update t5 set id=10 where name='AAA';

savepoint A;

update employee set id=20 where name='BBB';

savepoint B;

update employee set id=30 where name='CCC';

rollback to B;

select * from t5;

rollback;

select * from t5;

04.2-commit write <option>lgwrIO优化

2.png

1、wait、nowait控制什么时候将redo信息写入到redo logs

2、immediate、batch控制redo信息以怎样的方式写入到redo logs

一、手动指定提交选项

commit write wait;      //redofile完成后才使控制权返还给会话

commit write nowait;    //使控制权立即返还给会话

commit write batch;     //以批量方式将重做流写入到日志文件中,而不是每次提交都执行写操作。可以用这种技术来减少日志缓冲区刷新。

commit write immediate;  //立即写入日志缓冲区

二、commit_write默认选项

1、设置提交选项:

Alter system set commit_write = { nowait| wait| batch,wait | batch,nowait};

Alter setion set commit_write ={ nowait| wait| batch,wait | batch,nowait};

COMMIT默认方式

All clauses after the COMMIT keyword are optional. If you specify only COMMIT, then the default is COMMIT WORK WRITE IMMEDIATE WAIT.

2、提交选项的优先级

对于任何参数,如果完成设置后,则该参数在系统级执行。如果有会话级的设置,则会话级设置优先,而最后如果 COMMIT 语句后面有子句,则该子句优先。

04.3-事务的四大特征——ACID

一、Atomicity

要么完全被执行,要么完全不执行,以保证数据库的一致性,这种特性就叫原子性。如:网上转账……

1、语句级原子性,比如insert语句,如果由于check约束而失败,就不会插入数据。

2、过程级原子性,把PL/SQL匿名块也当作是语句,也具有原子性。

3、事务级原子性,比如A想要从自己的帐户中转1000块钱到B的帐户里。那个从A开始转帐,到转帐结束的这一个过程,称之为一个事务。在这个事务里,要做如下操作:

a 、从A的帐户中减去1000块。如果A的帐户原来有3000块,现在就变成2000块。

b、 在B的帐户里加1000块钱。如果B的帐户原来有2000块,现在变成3000块。

c、 要么一起成功(A帐户成功减少1000,同时B帐户成功增加1000),要么一起失败(A帐户回到原来状态,B帐户也回到原来状态)的操作叫原子性操作。

二、Consistency

数据库中的数据是时刻都有可能发生变化的,但是这种变化必须是可以接受的和合理的,即数据必须保持一致性——一致性保证某个特定时间点数据只有一个特定值。

1、语句级的读一致性=一个单独查询返回的数据是语句开始的单一时间点上的数据集。

句性一致性读,比如语句在开始执行之前获得当前的scn号为10001,而另个事务T2可能将该块的行进行修改,设置该行所在块的一致性标记,生成的 SCN10002,这种情况就需要应用undo回滚到scn10001的时刻,即为一致性状态,在单个语句执行期间这个值是不会改变的。

2、事务级的读一致性(可重复读)=所有数据的状态是在事务起始的状态,除非本事务修改的数据,这样就可以避免了不可重复读和幻像读。

三、Isolation

        多个并发的事务(含自治事务)间是避免影响互相分离和程度。比如read commited隔离级别:一个事务的影响在该事务提交前对其他事务都不可见。

四、Durability

事务提交了,那么状态就是永久的。即便是系统在遇到故障的情况下也不会丢失,这是数据的重要性决定的。

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第05部分-有哪几种DML锁?

本帖最后由 zcs0237 于 2013-6-13 20:41 编辑

 

05.1-两种基本锁类型——共享锁与排它锁

 

一、共享锁(Share Locks,即S锁,读锁)

1、共享锁只用于表级,Oracle在行上无S锁。

2、加了共享锁的对象,可以继续加共享锁,不能再加排他锁。

3、产生表级基本共享锁——4S

 

create table test (id int, name char(30));

lock table test in share mode;

select lmode,type,block from v$lock where TYPE='TM';

--     4     TM    0

 

二、排它锁(Exclusive Locks,即X锁,也叫独占锁,写锁)

1、一般要求在修改数据前要向该数据加排它锁,所以排它锁又称为写锁。

2、当执行DDL操作时,就需要在全表上加排他锁

3、加了排他锁后,不能再加任何锁。

4、产生行级基本排它锁——6X

 

create table test (id int, name char(30));

insert into test values(1,'zcs');

select lmode,type,block from v$lock where TYPE='TX';

 

--     6     TX     0  

 

05.2-按自动与主动划分——显式锁与隐式锁

一、隐含锁

Insert/Update/Delete/DDL/DCL会自动锁住需要加锁的资源以保护数据,这种锁是隐含的。

二、显式锁

有时这些自动的锁在实际应用时并不能满足需要,必须人工加for update/lock talble一些锁。

 

05.3-按数据的锁定时间分类——悲观锁、乐观锁

一、乐观封锁——容易被hung

认为死锁、锁等待等情况的出现机率不高,把锁定延迟到进行提交更新(直接update)的时候,才会正式对数据的冲突与否进行检测和处理。

1、准备工作

SQL>  create table t1 (id number,cash number);

insert into t1 values (1,1);

insert into t1 values (2,2);

commit;

/

2、第一个session:直接update乐观锁定

update t1 set id = 300 where id = 2;

3、第二个session:直接update,被hung住

update t1 set id = 300 where id = 2;

二、悲观封锁——影响并发性能(在此顺便了解select for update的用法)

认为在修改数据库数据的这段时间里存在着也想修改此数据的事务,在用户修改之前select…for update nowait打开一个游标,通知oracle锁定该行。接下来就可以update修改该行。

1、第一个session:悲观锁定,然后修改

SQL> select * from t1 where id=1 for update;

    1          1

SQL> update t1 set id = 200 where id = 1;

2、第二个session:再对同一行加锁会出现锁冲突

SQL> select * from t1 for update skip locked;

    2          2    //越过锁定的行,返回查询结果

SQL> select * from t1 for update nowait;

ERROR at line 1: //行已被其它会话锁定:直接抛ora-00054-resource busy,需重新select for update;

ORA-00054: resource busy and acquire with NOWAIT specified

SQL> select * from t1 where id = 1 for update wait 3;

ERROR at line 1: //等待3秒后提示锁冲突,无结果,系统会抛ora-30006

ORA-30006: resource busy; acquire with WAIT timeout expired

SQL> select * from t1 where id = 1 for update;

ERROR at line 1: //会等待行锁释放之后,再加锁,返回查询结果。

05.4-按锁的粒度分类——行级锁和表级锁

一、行级锁=eXclusive锁=写锁=TransactionX锁=LMODE6

08A61I44X2V2.png

1、TX锁是Oracle支持锁定的最低级别

行级锁是一种排他锁,防止其他事务修改此行,但是不会阻止读取此行的操作,也不会锁定同一个数据块中的其他数据行。

一个TX锁可以锁定该事务涉及的多行数据,它们都会“指向”该事务的一个相关TX锁。

2、insert、update、delete操作默认加行级锁与select for update默认加此锁。在执行过程中,行级别锁会阻止这一行上的任何其他DML,使其他会话排队等待这个事务执行,直至事务执行commit或rollback。

3、加行锁前自动加TM表级锁以保护表结构

→执行DML语句→语句解析→数据块读入db buffer

→到共享池的锁池中检查表级TM锁相容性(不逐行检查锁标志)→获得表的TM锁(保护表结构)

→申请TX行锁(在块头ITL表中申请一空闲项)

→到undo表空间申请undo段

→将uba-xid写入到刚刚在块头申请到的空闲ITL表项中→在行头写itl项目编号

→事务开始

→copy行记录到undo段→修改行记录内容并放入dirty list

→当其它用户想并发修改同一条记录时,会根据记录头的ITL“指针”读取数据块头部ITL表项的内容,查看flag标志以确认这个事务是否已经提交。

→如果没有提交,出现锁等待,这个用户会等待前一个用户的TX锁的释放。

→commit或rollback 释放TM锁和TX锁

二、表级锁(TM)

1、TM表级锁的种类有S,X,SR,SX,SRX五种,限制程度升序排列为2、3、4、5、6,级别越高并发度最小

3.png

2、SRX(SSX): 事务既对表加S锁+同时要在个别行上加X锁

3、由insert/update/delete获得的X锁在表级表征为RX锁

SYS@session1 > insert into test values(1,'zcs');

select lmode,type,block from v$lock where TYPE=('TM');

--         3 TM          0

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第06部分-模拟各种TM表级锁(lock table在工作中很少用)

本帖最后由 zcs0237 于 2013-6-10 10:26 编辑

 

1.png

06.1-Row Share=SS=2=作用:其它会话可DMLDDL

SYS@session1>  set heading off

grant dba to scott;

conn scott/tiger

drop table test purge;

create table test (id int, name char(30));

insert into test select object_id,object_name from all_objects where rownum<99;

commit;

一、会话1——得到2TM=SS

SCOTT@session1 > lock table test in row share mode;

select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--         2 TM          0          0

 

二、会话2——可以DDL,申请独占锁hung

SCOTT@session2 > alter table test drop column name;

Table altered.

SCOTT@session2 > lock table test in exclusive mode;   --hung

三、会话1——原因:2号行共享锁阻挡了6TM独占锁请求

SYS@session1 > select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--     2   TM          0          1

--     0   TM          6          0

 

06.2-Row eXclusive=SX=3=作用:其它会话可DML及加2号行共享TM

一、会话1——获得3TM行排它锁

SCOTT@session1 >  lock table test in row exclusive mode;

select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--  3    TM     0      0

二、会话2——其它会话可任意DML,可加行共享锁,不能加表共享锁

SCOTT @session2 >  update test set id=1 where rownum=1;

SCOTT @session2 >  rollback;

lock table test in row share mode;

select lmode,type,request,block from v$lock where sid in (select distinct sid from v$mystat);

--       2 TM          0          0

SCOTT @session2 > rollback;

lock table test in share mode;        --hung

三、会话1——原因:3号行排它TM锁阻挡了4TM表共享锁请求

SCOTT @session1 > select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--                     3     TM       0    1

--                     0     TM       4    0

 

06.3-Share=4=作用:其他会话不能DML,DDL,能加共享锁(若第一个s锁结束退出,第二个s锁继续避免出现幻读)

一、会话1——4TM表共享锁

SCOTT @session1 > lock table test in share mode;

select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--        4 TM          0          0

二、会话2——加第24TM表共享锁,若会话1退出仍然有一个4号共享TM锁继续防止DML避免出现幻读

SCOTT @session1 > lock table test in share mode;

select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--        4 TM          0          0

--        4 TM          0          0

SCOTT@session2 > rollback;

insert into test values(1,'zcs');       --hung

三、会话3——hung

SYS@session3 > select * from test  where rownum=1 for update;

四、会话1——原因:5号共享行排它阻挡了3TM行排它锁请求

SCOTT @session1 > select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--                   5       TM     0      1

--                   0       TM     3      0

 

06.4-Share Row eXclusive=SSX=5=作用:此时表只能被本会话专用,其它用户只读

一、会话1——事务既对表加S+同时要在个别行上加X

SCOTT@session1 > lock table test in share row exclusive mode;

select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--5       TM      0

二、会话2——其它会话可以加2号锁

SCOTT@session2 > lock table test in share update mode;

select lmode,type,request,block from v$lock where sid in (select distinct sid from v$mystat);

--     2     TM     0     0

SCOTT @session2 > rollback;

SCOTT @session3 > lock table test in row share mode;

select lmode,type,request,block from v$lock where sid in (select distinct sid from v$mystat);

--     2     TM    0     0

SCOTT @session3 > rollback;

三、会话2——其它会话DML会被hung

SCOTT @session2 > insert into test values(1,'zcs');

四、会话1——原因:5TM共享行排它锁阻挡了3TM行排它锁请求

SCOTT @session1 > select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--                    5      TM     0     1

--                    0      TM     3     0

 

06.5-eXclusive=6=作用:此时表只能被本会话专用锁定,其它用户只读

一、会话1——6TM表排它锁

SCOTT @session1 > lock table test in exclusive mode;

select lmode,type,block from v$lock where type in ('TM','TX');

--   6    TM          1

二、会话2——插入被hung

SCOTT @session2 > insert into test values(1,'zcs');

三、会话3——加表共享4号表锁被hung

SCOTT @session3 > lock table test in share mode;

四、会话1——原因:申请3TM行排它和4号表共享锁时被hung

SCOTT @session1 > select lmode, type,request,block from v$lock where TYPE in ('TM','TX');

--                  6        TM     0      1

--                  0        TM     3      0

--                  0        TM     4      0

 

06.6-禁止TM表级锁(降低一致性,无实际意义)

SQL> alter table test disable table lock;

select table_name, table_lock from user_tables where TABLE_NAME='TEST';

--TEST         DISABLED

SQL> Lock table emp in share mode;

--ORA-00069: cannot acquire lock -- table locks disabled for TEST

SQL> alter table test enable table lock;

update test set name='scott' where rownum=1;

select lmode,type,block from v$lock where type in ('TM','TX');

--         6  TX           0

SQL> alter table test enable table lock;

update test set name='scott' where rownum=1;

select lmode,type,block from v$lock where type in ('TM','TX');

--         3   TM          0

--         6   TX          0

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第07部分-追踪一个动作会申请哪些enqueue锁——10704 event

本帖最后由 zcs0237 于 2013-6-10 13:25 编辑

 

SYS@session1> create table test (id int, name char(30));

insert into test values(1,'zcs');

commit;

create index test_idx on test(ID);

07.1-跟踪100704 event

SYS@session1> !oerr ora 10704

10704, 00000, "Print out information about what enqueues are being obtained"

// *Cause:  When enabled, prints out arguments to calls to ksqcmi and

//          ksqlrl and the return values.

// *Action: Level indicates details:

//   Level: 1-4: print out basic info for ksqlrl, ksqcmi

//          5-9: also print out stuff in callbacks:  ksqlac, ksqlop

//          10+: also print out time for each line

SYS@session1> alter session set events '10704 trace name context forever, level 12';

alter index test_idx rebuild online;

alter session set events '10704 trace name context off';

oradebug setmypid;

oradebug tracefile_name;

--/u01/app/oracle/admin/orcl/udump/orcl_ora_4695.trc

07.2-分析100704 trace文件

$ grep 'mode=' /u01/app/oracle/admin/orcl/udump/orcl_ora_4723.trc|egrep 'TM,|TX,'

ksqcmi: TM,c8ee,0 mode=4 timeout=21474836

ksqcmi: TM,c8ee,0 mode=2 timeout=21474836

ksqcmi: TM,c8ee,0 mode=4 timeout=21474836

ksqcmi: TM,c8f4,0 mode=6 timeout=0

其中的”1b79″,”1c15″object_id16进制号,可以转换成10进制察看相应的object_name

SQL> select to_number('c8ee','xxxxxxxxxxxx') from dual;

                           51438

SQL> select to_number('c8f4','xxxxxxxxxxxx') from dual;

                           51444

SQL> select object_name,object_type from user_objects where object_id=51438;

TEST     TABLE

SQL> select object_name,object_type from user_objects where object_id=51444;

no rows selected

51444对应的是SYS_JOURNAL_ 的临时logging Table. Rebuild成功后被drop掉了。

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第08部分-加锁也可能带来麻烦——死锁

本帖最后由 zcs0237 于 2013-6-9 10:47 编辑

 

1、Deadlocks通常发生在两个或多个sessions对被彼此锁住的资源发出请求的情况下。其最常见的锁的类型为:row-level locks和block-level locks。

2、Oracle会自动侦察到死锁情况,并通过回滚其中一个造成死锁的语句,从而释放其中一个锁来解决它。需要说明的,如果一个事务中的某个语句造成死锁现象,回滚的只是这个语句而不是整个事务。

1.png

08.1-模拟00060死锁(oracle主动牺牲掉一个变为锁等待) +00054资源被占用

一、会话1:update id=1

SYS@session1>  conn / as sysdba

set heading off

grant dba to scott;

set sqlprompt "_user'@'session1> "

conn scott/tiger

SYS@session1> drop table test purge;

create table test (id int, name char(30)) ;

insert into test values(1,'name');

insert into test values(2,'name');

commit;

update test set name = 'name1' where id = 1;

二、会话2:update id=2

SYS@session2> set heading off

set sqlprompt "_user'@'session2> "

conn scott/tiger

SCOTT@session2> update test set name = 'name2' where id = 2;

三、会话1:update id=2,与会话1冲突,hung住

SCOTT@session1>  update test set name = 'name2' where id = 2;   --hung

四、会话2:update id=2,出现死锁,两个会话自动牺牲掉一个

SCOTT@session2>  update test set name = 'name1' where id = 1;   --hung

ERROR at line 1:

ORA-00060: deadlock detected while waiting for resource

五、会话3:模拟ORA-00054

SCOTT@session3>  set sqlprompt "_user'@'session3> "

conn scott/tiger

drop table test purge;

ORA-00054: resource busy and acquire with NOWAIT specified

08.2-.trc文件可看出哪个语句造成的阻塞

$ tail -n 1 alert_orcl.log

ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/orcl/udump/orcl_ora_3996.trc.

$ grep  --color=auto -A1 'Current SQL Statement:' /u01/app/oracle/admin/orcl/udump/orcl_ora_3930.trc

Current SQL Statement:

  update test set name = 'name1' where id = 1

$ grep  --color=auto -A4 'Rows waited on:' /u01/app/oracle/admin/orcl/udump/orcl_ora_3930.trc

Rows waited on:   //行级锁row-level locks

Session 154: obj - rowid = 0000C8E9 - AAAMjpAAEAAAAA/AAA  (dictionary objn - 51433, file - 4, block - 63, slot - 0)

Session 144: obj - rowid = 0000C8E9 - AAAMjpAAEAAAAA/AAB  (dictionary objn - 51433, file - 4, block - 63, slot - 1)

08.3-手工查找找出谁造成的阻塞(以及详细信息)

一、用v$locked_object查询被锁的对象

SYS@session3> set pagesize 999

select distinct OBJECT_ID from v$locked_object;

     51433

二、用v$lock查看谁是受害者

SYS@session3> set linesize 999

select SID, LMODE,TYPE,REQUEST,BLOCK from v$lock where LMODE=0;

       154     0   TX      6      0

三、用dba_blockers找出谁是坏蛋

SYS@session3> select * from dba_blockers;

--            144

四、用v$session找出坏蛋用哪个SQL_ID阻塞的

SYS@session3> select sql_id from v$session where blocking_session in (select * from dba_blockers);

1zjubay7kw9mu

五、用v$sql找出坏蛋用哪个SQL语句阻塞的

SYS@session3> select SQL_FULLTEXT from v$sql where SQL_ID='1zjubay7kw9mu';

update test set name = 'name1' where id = 1

 

08.4-手动释放锁等待

一、通过dba_blockers表中的HOLDING_SESSION字段可以查询到坏蛋的ID

SYS@session3>select * from dba_blockers;   select distinct blocking_session from v$session;

            159

二、使用v$session视图获取坏蛋sid和serial#

SYS@session3>select '-- alter system kill session ''' || sid || ',' || serial# || ''';'   FROM   v$session  WHERE   sid IN (select * from dba_blockers);

-- alter system kill session '146,49';

补充:把持有锁的和被阻挡的两个会话全部找出,解决resource busy不能执行DDL问题

conn / as sysdba

select '-- alter system kill session ''' || sid || ',' || serial# || ''';'   FROM   v$session  WHERE   sid IN (select SID from v$lock where LMODE=0 or block!=0);

-- alter system kill session '143,12';

-- alter system kill session '144,17';

三、kill掉相应的session

SYS@session3> alter system kill session '159,5' immediate;

System altered.

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

 

第09部分-加锁也可能带来麻烦——了解发生锁等待的各种情况

本帖最后由 zcs0237 于 2013-6-10 10:28 编辑

 

一、操作同一行数据引发的锁阻塞

Sess#1:获得独占锁select * from scott.dept for update

Sess#2: 申请的独占锁update scott.dept set dname='IT' where deptno=80;

二、实体完整性引发的insert锁阻塞

原因:多个会话试图在具有唯一性约束的列中插入相同的值。

解决方法:用oracle 提供的sequence来取值

Sess#1:insert into scott.dept(deptno,dname) values(60,'IT');

Sess#2:insert into scott.dept(deptno,dname) values(60,'IT');

三、参照完整性引发的锁阻塞

Sess#1:insert into scott.dept(deptno,dname) values(60,'IT');

Sess#2:insert into scott.emp(empno,ename,deptno) values(1234,'Bryan',60);

SQL> select sid, lmode, request from v$lock where REQUEST!=0;

SID   LMODE    REQUEST

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

142     0          4  

四、外键未加索引引发的锁阻塞

Sess#1:delete from scott.emp where 0=1;

Sess#2:delete from scott.dept where 0=1;

五、锁的排队机制引发的锁阻塞

Sess#1:update scott.emp set sal=5555 where empno=7499;

Sess#2:lock table scott.emp in share mode;

SQL> select sid, request from v$lock where REQUEST!=0;

           142      4   

六、ITL Slot引发的锁阻塞

若并发事务数量特别多超过ITL的Slot数量(10g中Maxtrans为255不可改),则会引起阻塞;

七、位图索引带来的阻塞

位图索引适合建在低基数列上面,在数据仓库比较常用,如果是在并发性要求较高的oltp系统就要慎重了,不当的应用,可能会带来严重的阻塞。

Session1> create bitmap index bidx_emp_job on emp(job);  --job字段建立了位图索引

Session1> DELETE EMP WHERE EMPNO=7369;

Session2> DELETE EMP WHERE EMPNO=7876;  --hung

 

源文档 <http://www.itpub.net/forum.php?mod=viewthread&tid=1795446&page=1#pid21478502>

创建时间:2022-03-30 20:54
浏览量:0