Oracle包被锁定的原因分析及解决方案

http://blog.csdn.net/jojo52013145/article/details/7470812

在数据库的开发过程中,经常碰到包、存储过程、函数无法编译或编译时会导致PL/SQL 无法响应的问题。碰到这种问题,基本上都要重启数据库解决,严重浪费开发时间。本文将就产生这种现象的原因和解决方案做基本的介绍。

  • 问题分析

从事数据库开发的都知道锁的概念,如:执行 Update Table xxx Where xxx 的时候就会产生锁。这种常见的锁在Oracle里面被称为DML锁。在Oracle中还有一种DDL锁,主要用来保证存储过程、表结构、视图、包等数据库对象的完整性,这种锁的信息可以在DBA_DDL_LOCKS中查到。注意:V$LOCKED_OBJECT记录的是DML锁信息,DDL锁的信息不在里面。

对应DDL锁的是DDL语句,DDL语句全称数据定义语句(Data Define Language)。用于定义数据的结构或Schema,如:CREATE、ALTER、DROP、TRUNCATE、COMMENT、RENAME。当我们在执行某个存储过程、或者编译它的时候Oracle会自动给这个对象加上DDL锁,同时也会对这个存储过程所引用的对象加锁。

了解了以上知识以后,我们可以得出结论:编译包长时间无响应说明产生了死锁。我们可以轻易的让这种死锁发生,举例:

1、     打开一个PL/SQL,开始调试某个函数(假设为:FUN_CORE_SERVICECALL),并保持在调试状态

2、     打开一个SQL Window,输入Select *From dba_ddl_locks aWhere a.name =‘FUN_CORE_SERVICECALL‘会发现一行记录:

3、     打开一个新的PL/SQL,重新编译这个函数。我们会发现此时已经无法响应了

4、     回到第一个PL/SQL ,重新执行Select *From dba_ddl_locks aWhere a.name =‘FUN_CORE_SERVICECALL‘我们将会看到如下记录:

5、     上述的情况表明发生了锁等待的情况。

在Oracle中DDL锁分为:Exclusive DDL Locks(排他的DDL)、Share DDL Locks(共享DDL锁)、Breakable Parse Locks(可被打破的解析锁)几类。篇幅所限,这里就不再详细介绍了。根据这个例子推理一下,当我们试图编译、修改存储过程、函数、包等对数据对象的时候,如果别人也正在编译或修改他们时就会产生锁等待;或者我们在编译某个存储过程的时候,如果它所引用的数据库对象正在被修改应该也会产生锁等待。这种假设有兴趣的兄弟可以测试下,不过比较困难。

  • 解决方案

碰到这种问题,如果知道是被谁锁定了(可以查出来的),可以让对方尽快把锁释放掉;实在查不出来只能手工将这个锁杀掉了。步骤如下:

1、     首先查出哪些进程锁住了这个对象,语句如下:

Select b.SID,b.SERIAL#

Fromdba_ddl_locks a, v$session b

Where a.session_id= b.SID

And a.name =‘FUN_CORE_SERVICECALL‘;

2、     执行如下语句杀进程:alter system kill session ‘sid,serial#‘

3、     执行了以上的语句后,有的时候不一定能够将进程杀掉。这个时候就需要连到数据库服务器上杀掉服务器端的进程了,查询语句:

Select spid, osuser, s.program

Fromv$session s, v$process p

Where s.paddr= p.addr

And s.sid =(上面查出来的SID)

4、     在服务器上执行如下语句:

#kill -9 spid(UNIX平台)

orakill sid thread(Windows平台SID是Oracle的实例名,thread是上面查出来的SID)

5、     执行完4步以后基本上就可以杀掉这些锁死的进程了,不放心的话可以再执行第一步确认下。

本文只能是说对这个问题做了初步分析,产生此问题的原因及解决方案涉及到很多Oracle的基本知识。如:DML语句,DDL语句;Oracle锁的机制;v$session 与 v$process之间关系等。有兴趣的兄弟可以更加深入的研究,欢迎跟我交流!

死锁是数据库经常发生的问题,数据库一般不会无缘无故产生死锁,死锁通常都是由于我们应用程序的设计本身造成的。产生死锁时,如何解决呢,下面是常规的解决办法:

1)执行下面SQL,先查看哪些表被锁住了: 
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;

2)查处引起死锁的会话
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;
这里会列出SID

3) 查出SID和SERIAL#: 
查V$SESSION视图: 
SELECT SID,SERIAL#,PADDR FROM V$SESSION WHERE SID=‘刚才查到的SID‘; 
这一步将得到PADDR

4)查V$PROCESS视图: 
SELECT SPID FROM V$PROCESS WHERE ADDR=‘刚才查到的PADDR‘; 
这一步得到SPID

5)杀死进程 
(1)在数据库中,杀掉ORACLE进程: 
ALTER SYSTEM KILL SESSION ‘查出的SID,查出的SERIAL#‘;

执行存储过程更新一个表中的数据的时候产生如下的错误:

SQL> exec update_jc_kxx_yxrq;

begin update_jc_kxx_yxrq; end;

ORA-20998: Err=-2049,Msg=0-ORA-02049: 超时: 分布式事务处理等待锁定
ORA-06512: 在"ICUSER.UPDATE_JC_KXX_YXRQ", line 36
ORA-06512: 在line 2

以sys用户登陆数据库查询死锁

SQL> select username,lockwait,status,machine,program from v$session where sid in
(select session_id from v$locked_object);

USERNAME LOCKWAIT STATUS
------------------------------ ---------------- --------
MACHINE
----------------------------------------------------------------
PROGRAM
------------------------------------------------
icdb
JDBC Thin Client

ICUSER 000000038A37C0C8 ACTIVE
icdb
JDBC Thin Client

说明数据库有死锁

然后使用一下语句查找被死锁的语句

SQL> select sql_text from v$sql where hash_value in
(select sql_hash_value from v$session where sid in
(select session_id from v$locked_object));

SQL_TEXT
--------------------------------------------------------------------------------
update JC_KXX SET LJXF =NVL ( LJXF , 0 ) + :1 , YE =:2 WHERE KH =:3
update jc_kxx set zt=‘07‘ where kh=‘1000530330‘

再使用以下语句查找被死锁的进程

SQL> SELECT s.username,l.OBJECT_ID,l.SESSION_ID,s.SERIAL#,
l.ORACLE_USERNAME,l.OS_USER_NAME,l.PROCESS
FROM V$LOCKED_OBJECT l,V$SESSION S WHERE l.SESSION_ID=S.SID;

USERNAME OBJECT_ID SESSION_ID SERIAL#
------------------------------ ---------- ---------- ----------
ORACLE_USERNAME OS_USER_NAME PROCESS
------------------------------ ------------------------------ ------------
ICUSER 30523 32 42463
ICUSER oracle

ICUSER 30523 28 25508
ICUSER oracle

ICUSER 30523 76 14781
ICUSER oracle

USERNAME OBJECT_ID SESSION_ID SERIAL#
------------------------------ ---------- ---------- ----------
ORACLE_USERNAME OS_USER_NAME PROCESS
------------------------------ ------------------------------ ------------
ICUSER 30523 24 37522
ICUSER oracle

使用一下语句把死锁的进程kill

alter system kill session ‘sid,serial#’; (其中sid=l.session_id)

如:SQL> alter system kill session ‘24,37522‘;

再次执行存储过程,错误没有了。语句执行成功!

Oracle包被锁定的原因分析及解决方案

时间: 2024-10-26 22:26:57

Oracle包被锁定的原因分析及解决方案的相关文章

AppStore IPv6-only审核被拒原因分析及解决方案

AppStore IPv6-only审核被拒原因分析及解决方案 http://www.jianshu.com/p/8edfdfa20b29 自2016年6月1日起,苹果要求所有提交App Store的iOS应用必须支持IPv6-only环境,背景也是众所周知的,IPv4地址已基本分配完毕,同时IPv6比IPv4也更加高效,向IPv6过渡是大势所趋. 然而在对IPv6进行兼容适配过程中,很多开发者在本地环境测试通过,却在App Store审核时被拒,这种情况下可以首先排查是否由DNS解析失败引起,

window.open浏览器弹出新窗口被拦截—原因分析和解决方案

最近在做项目的时候碰到了使用window.open被浏览器拦截的情况,在本机实验没问题,到了服务器就被拦截了,火狐有拦截提示,360浏览器拦截提示都没有,虽然在自己的环境可以对页面进行放行,但是对用户来说,不能要求用户都来通过拦截.何况当出现拦截时,很多小白根本不知道发生了啥,不知道在哪里看被拦截的页面,百思不得其解,后来查了一下,各家浏览器支持的不一样. 另外,可以发现,当window.open为用户触发事件内部或者加载时,不会被拦截,一旦将弹出代码移动到ajax或者一段异步代码内部,马上就出

Beforeunload打点丢失原因分析及解决方案

淘宝的鱼相在 2012 年 8 月份发表了一篇文章,里面讲述了他们通过一个月的数据采集试验,得到的结果是:如果在浏览器的本页面刷新之前发送打点请求,各浏览器都有不同程度的点击丢失情况,具体点击丢失率统计大家请看下图(数据日期为 2012 年 7 月份): 从图中可以看出,chrome,safari 这类 webkit 内核的浏览器在本页刷新之前发送打点,导致的丢失最为严重,分别为 61%,76%,而 ie8 丢失的情况最少,为7%. (具体大家可以参看此文:http://ued.taobao.c

在Activity的onCreate方法中显示PopupWindow导致异常的原因分析及解决方案

一.前言 在某些情况下,我们需要一进入Activity就显示PopupWindow,比如常见的选择界面.但由于PopupWindow是依附于Activity的,如果Activity没有创建完成,Activity还没完全显示出来就显示PopupWindow的话,会出现异常现象. 二.问题复现 我在Activity的onCreate()方法中调用如下方法: public void show( ){ if( null != mPopupWindow ){ mPopupWindow.showAtLoca

Android ListView异步加载图片乱序问题,原因分析及解决方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不

在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案

转:http://www.jianshu.com/p/89687f618837 原因分析   当我们在Android依赖库中使用switch-case语句访问资源ID时会报如下图所示的错误,报的错误是case分支后面跟的参数必须是常数,换句话说出现这个问题的原因是Android library中生成的R.java中的资源ID不是常数: 打开library中的R.java,发现确实如此,每一个资源ID都没有被声明为final: 但是当你打开你的主工程,在onClick.onItemClick等各种

关于JVM内存溢出的原因分析及解决方案探讨

前言:JVM中除了程序计数器,其他的区域都有可能会发生内存溢出. 0.什么是内存溢出 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出. 1.内存泄漏和内存溢出区别与联系 内存泄漏:系统分配的内存没有被回收. 内存溢出:分配的内存空间超过系统内存. 2.内存泄漏的原因分析   jvm由5大块组成:堆,栈,本地方法栈,程序计数器,方法区.栈它的主要记录方法的执行和对象的引用.堆则存在真正的引用的对象. 内存泄漏是由于使用不当,把一部分内存“

本机未装Oracle数据库时Navicat for Oracle 报错:Cannot create oci environment 原因分析及解决方案

因为要更新数据库加个表,远程桌面又无法连接...所以就远程到另外一台电脑,然后用navicat通过内网修改目标数据库. 一直用着navicat操作数据库,所以很速度的弄好然后新建连接进入数据库. 然而意外就发生了,Cannot create oci environment !!!什么鬼??? 用了这么久第一次碰到这个问题,各种百度发现是oci.dll文件版本不对,然后就是更换oci文件 因为远程的是Oracle 11g所以选择下面那个文件夹内的oci.dll文件,更新后成功. 在百度上也是翻了好

Connection reset原因分析和解决方案

在使用HttpClient调用后台resetful服务时,"Connection reset"是一个比较常见的问题,有同学跟我私信说被这个问题困扰很久了,今天就来分析下,希望能帮到大家.例如我们线上的网关日志就会抛该错误: 从日志中可以看到是Socket套接字在read数据时抛出了该错误. 导致"Connection reset"的原因是服务器端因为某种原因关闭了Connection,而客户端依然在读写数据,此时服务器会返回复位标志"RST",然