【问题标题】:No more data to read from socket没有更多数据可以从套接字读取
【发布时间】:2012-09-18 07:42:46
【问题描述】:

我的程序如下所示:

Declare 
       cur_1        Sys_Refcursor;
       cur_2        Sys_Refcursor;
       v_1          VARCHAR2(30);
       v_2          VARCHAR2(30);
       v_3          VARCHAR2(30);
       v_4          VARCHAR2(30);
Begin
       OPEN cur_1 for Select * from tab1@dblink1;
       Loop
           Fetch cur_1 into v_1, v_2;
           EXIT WHEN cur_1%NOTFOUND;   
           OPEN cur_2 for Select * from tab2@dblink1 where col1 = v_1 and col2 = v2;
           Loop
               Fetch cur2 into v_3, v_4;
               Exit when cur_2%notfound;    
               INSERT INTO local.tab3 values (v_1,v_2, v_3, v_4);
           END Loop;
           close cur_2;
       End Loop;
       close cur_1; 
END;

abobe 程序可以编译,但是当我运行它时出现以下错误:

没有更多数据可以从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
没有更多数据可从套接字读取
...(很少有'没有更多数据可以从套接字读取')

IO 错误:对等方重置连接:套接字写入错误
进程已退出。

有趣的是,当我注释掉整个内部循环时,程序运行时不会出错。所以我知道内部循环有问题(我尝试只注释内部循环中的插入语句并得到相同的错误)。

我的 localdbdblink1 数据库版本相同:

Oracle 数据库 11g 企业版 11.2.0.1.0 - 64 位生产

PL/SQL 版本 11.2.0.1.0 - 生产

核心 11.2.0.1.0 生产

适用于 64 位 Windows 的 TNS:版本 11.2.0.1.0 - 生产

NLSRTL 版本 11.2.0.1.0 - 生产

【问题讨论】:

  • Tab2 是否存在于您使用@dblink1 连接的数据库中?
  • 是的......当我通过 sqlplus 运行查询时,它返回一个结果集
  • @tbone:在循环中的 INSERT INTO local.tab3 值(v_1、v_2、v_3、v_4)之后添加了提交。不工作:(

标签: oracle plsql oracle11g


【解决方案1】:

排除“没有更多数据可从套接字读取”错误的一般建议。

这些错误通常是由另一个严重错误引起的,例如 ORA-600 错误。一个如此严重的问题,以至于服务器进程崩溃,甚至无法向客户端发送正确的错误消息。 (这些错误的另一个常见原因是由 SQLNET.EXPIRE_TIME 或其他杀死旧会话的进程引起的网络断开。)

查看警报日志以找出原始错误消息。

在此目录中查找文件 alert_[name].log:select value from v$parameter where name = 'background_dump_dest';

找到具体的错误消息和详细信息后,请访问 support.oracle.com。使用“ora-600 工具”,然后查找 ORA-600 消息后的第一个数字。

通常会有一篇或多篇文章针对特定类型的 ORA-600 错误。使用确切的版本和平台来缩小可能的错误列表。 (但如果文章中的“受影响的版本”是错误的,请不要感到惊讶。Oracle 声称“在 x.y 版本中修复”并不总是正确的。)

这些文章通常会更详细地说明问题是如何发生的、可能的解决方法以及通常涉及补丁或升级的解决方案。

实际上,您很少希望解决这些问题。 “典型”建议是联系 Oracle 支持以验证您是否确实遇到了同样的问题,获得补丁,获得许可并关闭环境,然后应用补丁。然后可能意识到补丁不起作用。恭喜,您只是浪费了很多时间。

相反,您通常可以避免对查询或过程进行细微的更改。 Oracle 中有很多特性,几乎总是有另一种方法可以做到这一点。如果代码最终看起来有点奇怪,请添加注释以警告未来的程序员:“这段代码看起来很奇怪,以避免出现 bug X,应该在版本 Y 中修复。”

此代码的具体建议

如果这真的是你的整个过程,你应该用这样的东西替换它:

insert into local.tab3(col1, col2, col3, col4)
select tab1.col1, tab1.col2, tab2.col1, tab2.col2
from tab1@dblink1 tab1
join tab2@dblink1 tab2
    on tab1.col1 = tab2.col1
    and tab1.col2 = tab2.col2;

一般来说,如果可能,您应该始终使用 SQL 执行操作。特别是如果您可以避免打开许多游标。 尤其是,如果您可以避免向远程数据库打开许多游标。

【讨论】:

  • 我找到了以下信息,但无法找出问题所在 - 线程 1 无法分配新日志,序列 478 2012 年 9 月 27 日星期四 11:16:45 线程 1 无法分配新日志,序列 479 私有链刷新未完成 当前日志# 3 seq# 480 mem# 0: C:\..\ORCL\REDO03.LOG 线程 1 前进到日志序列 481(LGWR 开关) 当前日志# 1 seq# 481 mem# 0: C: \..\ORCL\REDO01.LOG Thu Sep 27 15:46:13 2012 线程 1 无法分配新日志,序列 482 私有链刷新未完成当前日志# 1 seq# 481 mem# 0: C:\..\ORCL \REDO01.LOG
  • @acoolguy 我不确定这些消息的确切含义,但我认为它们不是问题所在。我的日志中有几十条类似的消息。您可能还需要检查远程数据库的日志。
  • 我稍微改变了实现,而不是内部 cur_2 sys_refcursor 我在新的 plsql 开始 - 结束块中使用简单游标,现在该过程有效!我仍然不知道为什么以前的实现不起作用n为什么这个起作用......有趣的思考......
  • 如果在任一数据库的日志中都找不到错误信息,我猜是网络错误。当我使用数据库链接进行临时查询时,有时会遇到类似的错误,让会话长时间打开,并且某些网络超时会终止连接。但我不知道如何解决这些问题。
  • @jonearles :SQLNET.EXPIRE_TIME 设置用于让数据库检测死连接。副作用是数据库将在 expire_time 之后发送一个空数据包,您可以将其用作保持活动状态。但并非所有防火墙都会将空包视为流量,并且无论如何都会断开您的连接。
【解决方案2】:

正如 jonearles 所提到的,您应该在一条 SQL 语句中编写它。

如果你坚持使用 PL/SQL:你自己做的工作太多了,声明变量、打开游标、循环、分配变量。考虑一下这个 PL/SQL:

begin
  for c1 in (select * from tab1@dblink1)
  loop
    for c2 in (Select * from tab2@dblink1 where col1 = c1.col1 and col2 = c1.col2)
    loop
      insert into local.tab3 values (c1.col1,c1.col2,c2.col1,c2.col2);
    end loop;
  end loop;
end;
/

【讨论】:

    猜你喜欢
    • 2018-01-07
    • 2012-07-16
    • 2015-02-04
    • 2011-12-11
    • 2015-05-12
    • 2021-01-23
    • 2017-06-17
    • 1970-01-01
    相关资源
    最近更新 更多