SQLException: 协议违规。Oracle JDBC驱动程序问题。

8
我会尽力为您翻译中文。以下是需要翻译的内容:

我遇到了以下异常:

java.sql.SQLException: Protocol violation
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:145)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:190)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:286)
at oracle.jdbc.driver.T4C80all.receive(T4C80all.java:766)
at oracle.jdbc.driver.T4CPreparedStatement.do0all8(T4CPreparedStatement.java:216)
at oracle.jdbc.driver.T4CPreparedStatement.fetch(T4CPreparedStatement.java:1225)
at oracle.jdbc.driver.OracleResultSetImpl.close_or_fetch_from_next(OracleResultSetImpl.java:373)
at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:284)

Oracle系统运行在Solaris 5.10上,版本为10.2.0.3.0。jdbc驱动程序运行在JDK 1.6.0_21上(如果重要的话,Java也在Solaris 5.10机器上运行)。我尝试了几种不同的Oracle thin drivers,包括最新的和那个看起来完全匹配Oracle版本的。
我运行的查询相当简单:“select * from some_table order by key1, key2, key3”,然后迭代结果集并写入文件。表约有1200万行,所以我期望这个过程会运行很长时间,但它似乎在进行5-15分钟后就停止了。每次运行时,它都会在不同的行上崩溃,所以我认为问题不在数据上。
我找到了Oracle警报日志,但我无法确定其中的任何内容与我的进程有关。即便如此,我也不是Oracle专家,也许有一个Oracle设置我需要查看。奇怪的是,我正在不同连接上运行大约五个这样的查询(有几个稍微复杂一些),只有两个最简单的查询遇到了这个问题。
如果您能提供任何帮助或想法来缩小问题范围,将不胜感激。

也许你的数据库服务器内存不足了?你是否在Java中正确关闭资源?这是在你的系列中第一个查询运行时发生的还是后面的查询之一? - Riggy
3个回答

8

对于未来需要查找此页面的人,以下是我们遇到的问题。

应用程序日志和Oracle跟踪记录了协议违规异常。

Oracle跟踪记录

这是来自Oracle跟踪文件的错误信息:

--- 检测到协议违规 ---

----- Dump Cursor sql_id=1j5kjnkncpp xsc=0x2a053a2a0 cur=0x2a052f1cf0 ---
----- Current SQL Statement for this session (sql_id=1jjns4k6npp) -----
        select xyz

从应用程序日志中

Caused by: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [72000]; error code [20000];

症状

这个异常偶尔会发生。堆栈跟踪中有不同的 sql,这非常令人困惑。使用 sql plus 运行 sql 没有问题。

根本原因

当 oracle 驱动程序尝试导出 CLOB 数据时,就会抛出异常。这只发生在少数记录中,而不是所有记录。数据本身是一个文件。从视觉上看,我们无法确定该数据出了什么问题。

为什么我们会在 oracle 日志中看到错误?

那么,如果这是驱动程序缺陷,为什么我们会在 oracle 跟踪中看到错误?从逻辑上讲,驱动程序错误应该仅限于应用程序日志。 原因是当协议违规发生时,连接被损坏。此连接被返回到连接池。任何用户或作业在使用该连接时都将无法工作并且会遇到错误。 这就是为什么它会在随机位置、使用随机用户时发生。

解决方案

短期修复方法是更改连接池中的此属性。我们正在使用 DBCP 连接池。

从 ds.setTestOnBorrow(false); 到 ds.setTestOnBorrow(true);

现在,当池返回损坏的连接到池中时,在应用程序借用此连接之前,它会测试其有效性。如果连接无法使用,则池将丢弃,然后应用程序获取一个新的/有效的连接。

如果启用连接池日志,您应该会看到通常被吞没的异常。

驱动程序升级

从 OJDBC 12.1.0.1 升级到 OJDBC 12.1.0.2 解决了问题,即使是有问题的行也是如此。

一些其他参考链接

https://confluence.atlassian.com/display/CONFKB/java.sql.SQLException%3A+Protocol+violation+caught+while+accessing+a+page+and+Oracle+DB+is+used


6

显然,在Java命令行中添加-d64可以解决此问题。看起来是Solaris 64位问题。


2
对我来说,升级我的ojdbc驱动程序解决了这个问题。我跳到了11.2.0.2.0版本,一切都很好。 - Muel

0
在我的情况下,使用Tomcat 8.5(标准连接池)、Oracle 19时,当Oracle发出警告信息(如“你的密码将在n天后过期”)时,Java连接对象会将其解释为错误。
我只是更改了同名的PASSWORD,问题就解决了。

1
你的回答可以通过添加更多的支持信息来改进。请[编辑]以添加进一步的细节,例如引用或文献资料,以便他人可以确认您的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接