ojdbc6中OraclePreparedStatement的ArrayIndexOutOfBoundsException异常BUG-6396242

现场信息

Caused by: java.lang.ArrayIndexOutOfBoundsException: -32203
        at oracle.jdbc.driver.OraclePreparedStatement.setupBindBuffers(OraclePreparedStatement.java:2677)
        at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:9270)
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:210)
        at weblogic.jdbc.wrapper.PreparedStatement.executeBatch(PreparedStatement.java:191)
        ... 6 more

运行时OraclePreparedStatement相关jar加载信息

 

排查解决

首先,看到有人遇到类似的问题,主要提到两点问题:

第一点,Ojdbc.jar和Oracle的版本有一个匹配关系的,对应关系如下图:

Oracle 版本JDK版本推荐jar包
Oracle 10g JDK 1.4 and 1.5 ojdbc14.jar
Oracle 11g JDK1.5 ojdbc5.jar
Oracle 11g JDK1.6 ojdbc6.jar

第二点:Ojdbc14版本在进行executeBatch操作的时候,如果参数多于32766会出现越界问题。

 

但是我的Ojdbc6.jar版本是:

Manifest-Version: 1.0
Implementation-Vendor: Oracle Corporation
Implementation-Title: ojdbc6.jar
Implementation-Version: Oracle JDBC Driver version - "11.1.0.6.0-Production+"
Implementation-Time: Tue Oct 30 03:33:58 2007
Specification-Vendor: Oracle Corporation
Created-By: 1.6.0 (Sun Microsystems Inc.)
Specification-Title: Oracle JDBC driver classes for use with JDK6
Specification-Version: Oracle JDBC Driver version - "11.1.0.6.0-Production+" 

Oracle版本

select * from v$version;
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

所以排除第一点版本匹配方面问题。

然后,从第二点数据量来看,我实际的批量提交量在56*1000=56000左右,而且已经有1000条记录正常写入,推测不完全是batch数量方面的问题。

理所当然尝试在开发环境复现问题,但是死活复现不了,怀疑开发和正式环境差异,添加VM参数-XX:+TraceClassLoading观察,发现tomcat加载的Ojdbc版本是ojdbc14,尽管ojdbc14没有问题,但目前看来这个还和中间件类加载顺序或者机制有关,并且肯定不能轻易的拿tomcat的ojdbc14去替换weblogic默认的ojdbc6。

测试环境将ojdbc14强行删掉只留ojdbc6后,终于复现了问题,与此同时如果把批量从1000降到500问题便消失,然后升到550问题重新出现(但是这时提交量在56*550=30800明显低于32768);再次说明不完全是batch数量的问题,从现象来看是在参数个数和行数达到某些条件同时批量到达一定长度后,多次提交才会触发此问题。

解决方法

1降低批量提交数量;2升级ojdbc6的版本。两种不同的解决方案,1并不是长久之计,还是要从根本上解决问题。

现在唯一能确定的就是ojdbc6出了问题,掉回头来搜索具体版本号:11.1.0.6.0,果然在11.1.0.7.0官方文档中找到了个修复相关bug的列表,

 

下载11.1.0.7.0新版的ojdbc6之后问题解决

原因分析

反编译后对比新旧两个版本的ojdbc6,定位到错误抛出方法setupBindBuffers,发现其中只有一行代码发生变动

 但是由于反编译的代码隐去了很多具体意义变量,这里只能初步判断就是此处附近取值时发生了数组越界异常; 

思考总结

这里对模拟线上环境使用了arthas进行了类加载定位,但是对于没有安装arthas的环境,如何才能获取到jar具体的加载信息这个需要进一步了解jvm相关tools。

排查过程中开发测试环境前期始终不能复现bug这个问题应该在发布、测试中引起注意,中间件的差异点要有预期。中间件的类加载器、加载机制相关内容需要进一步了解。

原文地址:https://www.cnblogs.com/elfcafe/p/12974826.html