oracle查看锁表和解锁

视图v$lock的列。

v$lock中的常用列有以下列:

  • sid:持有锁的会话SID,通常与v$session关联。

    获取当前会话SID:select USERENV('SID') from DUAL

  • type:锁的类型,其中TM表示表锁或DML锁TX表示行锁或事务锁,UL表示用户锁。我们主要关注TX和TM两种型的锁,其它均为系统锁,会很快自动释放,不用关注。

  • lmode:会话保持的锁的模式。

  • ID1,ID2: ID1,ID2的取值含义根据type的取值而有所不同。

  • request: request=6说明该session正在等待一个lmode为6的锁

lmode

当 Oracle执行 DML 语句时,系统自动在所要操作的表上申请 TM 类型的锁。当 TM锁获得后,系统再自动申请 TX 类型的锁,并将实际锁定的数据行的锁标志位进行置位

TM 锁包括了SS 、 SX、 S 、X 等多种模式,在数据库中用 0 -6 来表示。不同的 SQL 操作产生不同类型的 TM锁:

  • 0=None;
  • 1=Null ;
  • 2=Row-S (SS,行级共享锁,其他对象只能查询这些数据行),sql操作有select for update、lock for update、lock row share;
  • 3=Row-X (SX,行级排它锁,在提交前不允许做DML操作),sql操作有insert、update、delete、lock row share;
  • 4=Share(共享锁),sql操作有create index、lock share;
  • 5=S/Row-X (SSX,共享行级排它锁),sql操作有lock share row exclusive;
  • 6=Exclusive(排它锁),alter table、drop table、drop index、truncate table、look exclusive等DDL

ID1,ID2

(1)对于TM 锁ID1表示被锁定表的object_id 可以和dba_objects视图关联取得具体表信息,ID2 值为0;

(2)对于TX 锁ID1以十进制数值表示该事务所占用的回滚段号和事务槽slot number号,其组形式: 0xRRRRSSSS,RRRR=RBS/UNDO NUMBER,SSSS=SLOT NUMBER,ID2 以十进制数值表示环绕wrap的次数,即事务槽被重用的次数。实际上这两个字段构成了事务在回滚段中的位置

当锁产生时,以下图为例说明v$lock:

img

img

1、图中存在两个session分别是36和37,session 37的BLOCK=1意味着该session拥有一个锁,并阻塞了其他session的对该锁的请求(如果要处理死锁这是根源)。该锁的类型由TY定义,模式由LMODE字段定义;

2、session 36的request=6说明该session正在等待一个lmode为6的锁,而该锁的拥有者正是session 37。

3、对于TM锁,ID1值就是加锁的段对象,可以是表或者表分区,此时ID2一般为0;对于TX锁,这两个字段构成该事务在回滚段中的位置。

对于死锁的处理流程

单个死锁处理步骤

  1. 查找锁,阻塞的session和被阻塞session的sid:

set linesize 1200
COL USERNAME FOR A15
COL EVENT FOR A15
COL SID FOR 999999
COL INST_ID FOR 99


```sql
select inst_id,sid, username, event, blocking_session,
seconds_in_wait, wait_time
from gv$session where state in ('WAITING')
and wait_class != 'Idle';

img

可以看到sid为37的会话阻塞了sid为36的会话,我们要处理的是37的这个会话,将这个会话杀死。

  1. 查找session sid对应的操作系统的spid,并且杀死会话

    select  b.spid,a.sid,a.username,a.program,a.machine  from v$session a,v$process b where a.paddr=b.addr and a.type='USER';
    

    img

    这个sid为37的会话对应的操作系统的spid是7188,在操作系统用户下使用root使用kill -9 7188就行了,将阻塞的会话杀掉,这样阻塞就会消失。

批量杀死会话

如果一步到位杀死会话省去上面两个步骤运行下面SQL语句就行

杀阻塞的会话释放锁

set lines 900 pages 900  
col BLOCK for 9  
col LMODE for 9  
col INST_ID for 9  
col REQUEST for 9  
col SID for 999999  
select /*+ rule */a.INST_ID,
       a.SID,
       a.TYPE,
       LMODE,
       REQUEST,
       CTIME,
       BLOCK,
       'ps -ef |grep ' || c.spid,
       decode(LMODE, 0, null, 'kill -9 ' || c.spid) kill,
       'kill -9 ' || c.spid,
       d.sql_id,
       ID1,
       ID2
  from gv$lock a, gv$session b, gv$process c, gv$sqlarea d
 where (a.ID1, a.ID2, a.TYPE) in
       (select ID1, ID2, TYPE from gv$lock where request > 0)
   and a.sid = b.sid
   and a.inst_id = b.inst_id
   and a.inst_id = c.inst_id
   and b.inst_id = d.inst_id(+)
   and a.sid=b.sid
   and b.paddr = c.addr
   and b.sql_id = d.sql_Id(+)
 order by inst_id, lmode desc;

img

查看锁表和解锁例子

以下几个为相关表

SELECT * FROM v$lock;
SELECT * FROM v$sqlarea;
SELECT * FROM v$session;
SELECT * FROM v$process ;
SELECT * FROM v$locked_object;
SELECT * FROM all_objects;
SELECT * FROM v$session_wait;

查看被锁的表

select b.owner,b.object_name,a.session_id,a.locked_mode from 
v$locked_object a,dba_objects b where b.object_id = a.object_id;

查看那个用户那个进程照成死锁

select b.username,b.sid,b.serial#,logon_time from 
v$locked_object a,v$session b where a.session_id = b.sid order by b.logon_time;

查看连接的进程

SELECT sid, serial#, username, osuser FROM v$session;

查找到数据库中所有的DML语句产生的锁

查出锁定表的sid, serial#,os_user_name, machine_name, terminal,锁的type,mode

SELECT s.sid, s.serial#, s.username, s.schemaname, s.osuser, s.process, s.machine,
s.terminal, s.logon_time, l.type
FROM v$session s, v$lock l
WHERE s.sid = l.sid
AND s.username IS NOT NULL
ORDER BY sid;

这个语句将查找到数据库中所有的DML语句产生的锁,还可以发现,任何DML语句其实产生了两个锁,一个是表锁,一个是行锁。

杀掉进程 sid,serial#

alter system kill session 'sid,serial#' 

这个也得到最终要杀死阻塞会话的spid,使用kill -9 7188就可以消除阻塞释放锁。

posted @ 2021-04-14 12:04  satire  阅读(1289)  评论(0编辑  收藏  举报