[转][工地][存]Oracle触发器死锁问题解决

摘自http://blog.itpub.net/12932950/viewspace-607691/

这两天一直在因为系统初期设计原因导致的一个触发器问题。
问题如下:
有表T,有客户编号、账户编号及地址三个字段(为方便起见以最少字段描述)。
一个客户编号下可能存在多个账户编号(3个或4个)。
假设客户编号C0下有A1、A2、A3三个账户编号。
       
现在对账户编号A1的地址字段进行了更新,要求通过触发器同时更新客户编号C0下的另外两个账户A2和A3的地址字段。

通过实际的触发,发现存在着一个非常致命的问题:
      
由于指定的是自治事务触发器(即指定了pragma
autonomous_transaction),假设为T1。每次更新表时触发都是独立的。因此就产生了死循环和死锁的问题。
因为更新了A1,则T1触发。T1内去找到同个客户编号下的A2和A3。然后先更新A2,此时便又触发了T1。然后又找到同个客户编号下的A1和A3。然后先更新A1,而由于先前第一次更新已经锁住了A1,再次更新就会导致死锁。因为先前的A1更新需要现在的A1先完成。而现在的A1更新却被先前的A1更新阻塞了。
       
从上面可以看出,如果可以找到这样一个办法,将锁住的行找出来,然后在每次更新之前都判断一下该行是否被锁住。如果锁住则跳到下一条记录进行处理。没锁住则继续更新。
      
实际上这只是理想的情况,的确可以通过查询v$lock v$session v$locked_object查到被锁住的行:
select
ta.account_no, o.object_name, ta.rowid
 from
v$session s, ttest ta, user_objects o, v$locked_object lo
where
lo.SESSION_ID = s.SID
 
and lo.OBJECT_ID = o.object_id
 
and dbms_rowid.rowid_object(ta.rowid) = o.data_object_id
 
and o.object_id = s.ROW_WAIT_OBJ#
 
and dbms_rowid.rowid_relative_fno(ta.rowid) = 
s.ROW_WAIT_FILE#
 
and dbms_rowid.rowid_block_number(ta.rowid) = s.ROW_WAIT_BLOCK#
 
and dbms_rowid.rowid_row_number(ta.rowid) = s.ROW_WAIT_ROW#
但是通过实际调试发现。这个记录的并不是当时被锁住的所有记录。而是最后一次被锁住的一条记录。什么意思呢?也就是说当时可能有几条记录被锁住。但是这个SQL所查出来的是执行所有锁行操作的语句后,最后一次被锁住的行。也就是失去了即时判断的可能性。
      
想通过另外的方法去找到这个被锁住的行我网上也搜索过无数遍了。都没有实际解决方案。可能这么做的人很少吧。
      
最后想到了一个办法,就是通过临时表的方法去记录被更新的行。一旦触发T1,就往临时表记录这一行的rowid和对应的锁定标识。然后在更新的时候判断
是否已经存在于该表中。如果有则不更新,没有则往下更新。更新并提交后该行
锁标识清零。进入下一次循环。
      
这个临时表是会话级的。因此在触发器循环触发过程中都是处于同一个数据环境下。方便了对指定行的加锁与解锁(其实是设定行锁定状态)。
下一篇准备讲述此次解决死锁问题而学习到的关于Oracle锁的一些方面的知识。
(备注:如果不指定自治事务触发器,则无法修改触发器触发所在的表)

时间: 2024-10-21 17:31:11

[转][工地][存]Oracle触发器死锁问题解决的相关文章

ORACLE中死锁

ORACLE中死锁的知识点总结   死锁的概念 什么是死锁呢? 其实我们生活中也有很多类似死锁的例子. 我先举一个生活中的例子:过年回家,父亲买了一把水弹枪,儿子和侄子争抢着要先玩,谁也不让谁,拆开包装后,一个抢了枪, 一个逮住了子弹和弹夹.两个都争着要先玩,但是都互不相让.结果两个人都玩不了.如果儿子要先玩,就必须让侄子把子弹和弹夹给他,如果侄子要先玩,就必须让儿子把枪给侄子.他们就这样对峙了十几分钟,互不相让. 我出来调停,让儿子把枪先给侄子玩,每个人玩十分钟.然后两个人开开心心一起玩起来.

ORACLE中死锁的知识点总结

  死锁的概念 什么是死锁呢? 其实我们生活中也有很多类似死锁的例子. 我先举一个生活中的例子:过年回家,父亲买了一把水弹枪,儿子和侄子争抢着要先玩,谁也不让谁,拆开包装后,一个抢了枪, 一个逮住了子弹和弹夹.两个都争着要先玩,但是都互不相让.结果两个人都玩不了.如果儿子要先玩,就必须让侄子把子弹和弹夹给他,如果侄子要先玩,就必须让儿子把枪给侄子.他们就这样对峙了十几分钟,互不相让. 我出来调停,让儿子把枪先给侄子玩,每个人玩十分钟.然后两个人开开心心一起玩起来.其实这就是一个活生生的死锁(De

oracle触发器、序列、任务计划练习一例

今天在闲暇时间练习了一下oracle任务计划,具体详情如下 1.创建表 TBL_TIME create table tbl_time( id number not null,    /*id号*/ vsecond varchar2(2),   /* 秒*/ vtime varchar2(10)    /*当前时间*/ ) 2.创建序列 seq_tbltime create sequence seq_tbltime start with 1 increment by 1 nomaxvalue no

oracle 触发器与事务

(1)如果外部事务撤销,触发器形成的变更是否会撤销?如果触发器操作失败,是否会导致外部SQL失败,从而导致事务撤销(2) 事务回滚时,触发器形成的变更是否会撤销:(3) 触发器失败时,外部SQL是否会返回错误:如果会,则研究如何不返回错,如果不会,则研究如何会返回错误:(4) 触发器失败时(插入两条记录,前者成功,后者失败),事务回滚时触发器形成的变更是否会撤销:(5) 触发器失败时(插入两条记录,前者成功,后者失败),事务提交时触发器形成的变更是否会撤销: 答 在oracle中,对触发器的限制

oracle 触发器 学习笔记

触发器 是特定事件出现的时候,自动执行的代码块.类似于存储过程,但是用户不能直接调用他们. 功能: 1. 允许/限制对表的修改 2. 自动生成派生列,比如自增字段 3. 强制数据一致性 4. 提供审计和日志记录 5. 防止无效的事务处理 6. 启用复杂的业务逻辑 开始 create trigger biufer_employees_department_id before insert or update of department_id on employees referencing old

Oracle触发器如何调用Java实现Openfire消息发送

写在前面,要想实现整个过程的成功执行请先准备以下文件: 1. 登陆Openfire服务端以及Spark客户端相关程序(openfire_4_0_1.exe.spark_2_7_6.exe) 2. 连接Openfire和Oracle相关的jar包(presence.jar.smack.jar.smackx-debug.jar.smackx.jar.ojdbc.jar)  Step1:安装Openfire服务端并配置数据库连接,配置参考<Openfire服务器安装与配置教程> Step2:在Ecl

oracle触发器使用总结

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! oracle触发器使用总结 1.说明 1)触发器是一种特殊的存储过程,触发器一般由事件触发并且不能接受参数,存储器由语句块去调用 2)触发器分类: 1.DML触发器: 创建在表上,由DML事件引发 2.instead of触发器: 创建在视图上并且只能在行级上触发,用于替代insert,delete等操作(由于oracle中不能直接对有两个以上的表建立的视图进行DML操作,所以给出替代触发器,它是专门为进行视图操作的一种处理方法)

Oracle常见死锁发生的原因以及解决方法

Oracle常见死锁发生的原因以及解决办法 一,删除和更新之间引起的死锁 造成死锁的原因就是多个线程或进程对同一个资源的争抢或相互依赖.这里列举一个对同一个资源的争抢造成死锁的实例. Oracle 10g, PL/SQL version 9.2 CREATE TABLE testLock(  ID NUMBER, test VARCHAR(100)  ) COMMIT INSERT INTO testLock VALUES(1,'test1'); INSERT INTO testLock VAL

Oracle 表死锁 解决

问题:更新的Update语句一直在更新 卡在执行update语句的地方. 清除的方法: Oracle表死锁解除 我是在plsql中处理 1.先查询 select * from v$locked_object v, dba_objects o where v.object_id = o.object_id 2.记录死锁表的session_id 3.Tools →Sessions 找到session_id对应Sessions窗口里的Sid(可以排下序再找比较快),在Status 列 右键 Kill.