dblink的异常处理

[复制链接]
查看11 | 回复8 | 2007-10-20 08:38:44 | 显示全部楼层 |阅读模式
我自己的数据库A,在做某一个操作的时候,需要从数据B中取一个信息;
这个信息也不是特别重要,如果失败了,也可以以后再取,不影响业务;
连接数据库B的方法是用DBLink
这个操作对于的存储过程是:
create procedure xxx
..
begin
...
BEGIN

select b.field1 into .. fromtable1圈B.US.ORACLE.COM
EXCEPTION

WHEN OTHERS THEN

NULL; --执行不了,也无所谓,继续做下面的
END;
..
end;
也就是说,在执行这个过程的时候,就算B服务器关闭了或网络不通;A服务器也能正常的把这个过程跑完;
但是关键问题是:
如果B服务器和A服务器不能正常连接,那么这个过程执行到 select b.field1 into .. fromtable1圈B.US.ORACLE.COM 的时候,程序会“死”很长时间;
这个存储过程正常执行时间一般为0.08秒,但是如果B服务器不通,那么因为这会话执行不下去而等待的时间是15分钟(900秒),相差了1万倍;

我的解决方法是:
1.在select b.field1 into .. fromtable1圈B.US.ORACLE.COM 后面加一个参数,
比如select b.field1 into .. fromtable1圈B.US.ORACLE.COM [timeout=1秒] ,这样就让它顶多执行1秒,时间到了,就报异常到exception,然后继续;
当然这个 [timeout=1秒] 这种写法是不对的,我只是通过它表达这个意思,估计oracle里没有提供让存储过程里的某一句话设置最长执行时间的功能;
如果对某句话没有这样的处理,那么对于整个存储过程是不是可以设置timeout的时间,如果可以设置,我把这句话封装成一个小过程,从而设置它的timeout时间;
也许大家会说,直接在客户端程序里设置timeout,我觉得这样不灵活,而且一旦设置了,那么肯定会导致执行失败,而且有的复杂的过程,确实需要花费很长的执行时间,
设置客户端的timeout不太好;
2.前台语言java,c#里都有多线程的方法,我想是不是可以把这段话设置成多线程的方法,但是pl/sql里内部某段话设置成多线程好像不能实现,我记得用pipe管道可以,不过不熟,而且如果写起来太麻烦,也容易出问题; 要不就是嵌入java实现,是不是一样很复杂。
[ 本帖最后由 qingyun 于 2009-12-28 10:59 编辑 ]
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
一切通过网络传输的东西都是不可相信的
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
可能要去操作系统设置TCP/IP的TIMEOUT时间。你可以研究一下TNSPING是怎么实现的然后做类似的事情,如果连接不通就不要用。
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
青云,这个问题怎么解决的?
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
1. 为你的用户授权查询dba_jobs_running.
2. 创建一个过程ptest, 只包含一句
select 1 into ... from dual@dblink;
3. 创建一个job, job的what是ptest
4. 在你的过程xx中,用以下代码:
create procedure xxx
..
begin
...
dbms_job. run(thejob);
dbms_lock.sleep(时间长度);
查询dba_jobs_running看上面的job是否仍然在运行
if 还在运行 then
网络不通的处理
else
做你本来该做的事情
end if;
..
end;
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
上面的方法通过JOB来异步执行检查,避免过长时间等待,但是在网络通的情况下也要SLEEP.
可以改用DBMS_PIPE和JOB进行通讯,如果是通的马上就能知道。
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
标记下,学习了
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
学习
回复

使用道具 举报

千问 | 2007-10-20 08:38:44 | 显示全部楼层
原帖由 qingyun 于 2009-12-28 10:52 发表
我自己的数据库A,在做某一个操作的时候,需要从数据B中取一个信息;
这个信息也不是特别重要,如果失败了,也可以以后再取,不影响业务;
连接数据库B的方法是用DBLink
这个操作对于的存储过程是:
create procedure xxx
..
begin
...
BEGIN

select b.field1 into .. fromtable1圈B.US.ORACLE.COM
EXCEPTION

WHEN OTHERS THEN

NULL; --执行不了,也无所谓,继续做下面的
END;
..
end;
也就是说,在执行这个过程的时候,就算B服务器关闭了或网络不通;A服务器也能正常的把这个过程跑完;
但是关键问题是:
如果B服务器和A服务器不能正常连接,那么这个过程执行到 select b.field1 into .. fromtable1圈B.US.ORACLE.COM 的时候,程序会“死”很长时间;
这个存储过程正常执行时间一般为0.08秒,但是如果B服务器不通,那么因为这会话执行不下去而等待的时间是15分钟(900秒),相差了1万倍;

我的解决方法是:
1.在select b.field1 into .. fromtable1圈B.US.ORACLE.COM 后面加一个参数,
比如select b.field1 into .. fromtable1圈B.US.ORACLE.COM [timeout=1秒] ,这样就让它顶多执行1秒,时间到了,就报异常到exception,然后继续;
当然这个 [timeout=1秒] 这种写法是不对的,我只是通过它表达这个意思,估计oracle里没有提供让存储过程里的某一句话设置最长执行时间的功能;
如果对某句话没有这样的处理,那么对于整个存储过程是不是可以设置timeout的时间,如果可以设置,我把这句话封装成一个小过程,从而设置它的timeout时间;
也许大家会说,直接在客户端程序里设置timeout,我觉得这样不灵活,而且一旦设置了,那么肯定会导致执行失败,而且有的复杂的过程,确实需要花费很长的执行时间,
设置客户端的timeout不太好;
2.前台语言java,c#里都有多线程的方法,我想是不是可以把这段话设置成多线程的方法,但是pl/sql里内部某段话设置成多线程好像不能实现,我记得用pipe管道可以,不过不熟,而且如果写起来太麻烦,也容易出问题; 要不就是嵌入java实现,是不是一样很复杂。


青云,最终解决没有,我也想套用你的方案。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行