ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 谁锁住了我的数据表

谁锁住了我的数据表

原创 Linux操作系统 作者:realkid4 时间:2011-02-16 14:35:47 0 删除 编辑

 

实际开发和测试中,经常遇到数据对象有意无意锁住的情况。怎么样最快速准确的定位到锁住对象表的用户和机器呢?

 

下面是笔者写的一段脚本,可以发现指定对象(特定Schema和特定对象)上所有加锁对象和用户。在Oracle中,只有独占锁是唯一的,共享锁可能存在多个用户同时锁住。笔者曾经遇到过使用pl/sql developer添加数据,程序反复崩溃,最后发现这个对象表上加三次锁的情况。

 

 

下面是针对这种情况,笔者试着写的一段脚本。执行环境可以是sql*plus或者pl/sql developer command window均可。只要输入锁住对象所在的schema和名称,就可以定位到锁定用户信息。

 

 

select p.SPID, p.SERIAL# as proserial,p.PID as pid, s.SID as sessionid,

       s.SERIAL# as sessseri, s.USERNAME,s.OSUSER,s.MACHINE,

       s.PROGRAM,s.ACTION,s.STATUS

from v$session s, v$process p

where s.PADDR=p.ADDR and s.SID in (

select session_id from v$locked_object

where object_id in (select object_id from dba_objects

where wner='&schema' and object_name='&name'));

 

 

其中的结果列中:

 

列名

含义

备注

SPID

操作系统级别的进程编号

Linux/Unix环境下,使用ps –ef可以查看到进程编号;而在windows环境下,是指定Oracle.exe进程中的线程编号!要注意区别!

PROSERIAL

操作系统级别的进程系列号

进程有一个系列号,在查找和kill的时候要使用;

PID

Oracle内部进程编号

Oracle内部的编号,可以查找v$process视图进行定位;

SESSIONID

锁表会话ID

会话id

SESSSERI

锁表会话系列号

会话系列号,使用alter system kill session

USERNAME

会话登录用户名

登录用户的数据库登录名;

OSUSER

登录操作系统用户名

登录用户在操作系统上的名称;

MACHINE

登录客户端机器

客户端主机名;

PROGRAM

登录程序名称

登录程序名,如plsqldev.exe或者sqlplus.exe

ACTION

进行行为描述

进行行为的简单描述;

STATUS

当前会话状态

当前会话状态,可以为ActiveInActive等;

 

使用该脚本比较简单,只要把里面的SQL粘贴在sqlplus或者其他开发工具上就可以了。下面以sqlplusw为例,进行演示。

 

 

SQL*Plus: Release 10.2.0.1.0 - Production on 星期三 2 16 14:08:51 2011

 

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

 

SQL> conn sys/acca@otstest as sysdba;

已连接。

SQL> select * from scott.emp for update nowait; //尝试获取独占!

select * from scott.emp for update nowait

                    *

1 行出现错误:

ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源 //报错,emp对象被锁住了!!

 

 

调用脚本。

 

 

SQL> select p.SPID, p.SERIAL# as proserial,p.PID as pid, s.SID as sessionid,

  2         s.SERIAL# as sessseri, s.USERNAME,s.OSUSER,s.MACHINE,

  3         s.PROGRAM,s.ACTION,s.STATUS

  4  from v$session s, v$process p

  5  where s.PADDR=p.ADDR and s.SID in (

  6  select session_id from v$locked_object

  7  where object_id in (select object_id from dba_objects

  8  where wner='&schema' and object_name='&name'));

输入 schema 的值:  SCOTT

输入 name 的值:  EMP

原值    8: where wner='&schema' and object_name='&name'))

新值    8: where wner='SCOTT' and object_name='EMP'))

 

SPID          PROSERIAL        PID  SESSIONID   SESSSERI USERNAME        OSUSER   MACHINE                                                          PROGRAM          ACTION                           STATUS

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

3584                205         15        159       9529 SCOTT                          ACCA-119HS63YXC\Guest          WORKGROUP\XXX-PC                                             plsqldev.exe                                                     Command Window - New             INACTIVE

 

 

 

这样,就可以找到用户信息了。

 

下面解决就容易了,可以联系相关人员解开对象锁,或者联系管理员kill掉会话和进程。这部分讨论可以参见笔者之前的blog

kill会话过程分析(http://space.itpub.net/17203031/viewspace-683786 )。

 

 

最后,有兴趣可以来分析一下脚本使用的原数据视图。

 

ü         v$process:记录了Oracle进程的信息,包括Server Process和后台进程,其中的SPIDSerial,以及ADDR是描述进程在操作系统层面的信息;

ü         v$session:记录会话信息,表示一个登录对应的会话内容;

ü         v$lock_objects:当前被锁住对象的信息;

ü         dba_objects:所有数据库对象的列表,提供唯一object_id的来源;

ü          

 

 

有一点要注意,并不只是数据表会被锁住,存储过程代码、视图等对象都有被锁住和引起连带锁住的风险。在本脚本中数据这些对象的名称,也是有一定作用的。

 

 

原则上说,当我们强制断开数据库Oracle客户端之后,实例会自动检测到连接的断开,并且回收资源、撤销事务和解锁对象。这种操作一般是要有一定时间(几秒钟或者十几分钟),如果长时间没有释放资源,也就需要DBA的干预进行手工对象解锁。

 

手工解锁对象有两个层面,会话层面和OS层面。一般我们采用从低到高的选择方案。当会话层面的kill不能完全释放资源的时候,才会考虑使用OS层面。一些特殊情况,如JOB进程,是需要直接OS层面杀死进程的。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-687333/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
求道~

注册时间:2010-11-30

  • 博文量
    545
  • 访问量
    7677644