使用SqlParameterSource插入27列数据至数据库表时触发数组越界异常
问题背景
我在使用NamedParameterJdbcTemplate向包含27列的Oracle数据库表插入数据时,遇到了ArrayIndexOutOfBoundsException,错误源自Oracle JDBC驱动的SQL解析阶段。以下是我的代码配置和错误信息:
代码片段
参数构建:
SqlParameterSource parameters = new MapSqlParameterSource() .addValue("Id", 12345678) .addValue("packageId", info.getIrocPkgId()) .addValue("isAsgn", 1) .addValue("startTm", info.getStartTm()) .addValue("endTm", info.getEndTm()) .addValue("type", ConstantVal.TASK) .addValue("note", ConstantVal.ETA + ":" + info.getEta()) .addValue("fdbk", ConstantVal.EMPTY) .addValue("sCnt", 1) .addValue("aCd", ConstantVal.ETA) .addValue("isAuto", 1) .addValue("dfltStartTm", info.getStartTm()) .addValue("dfltEndTm", info.getEndTm()) .addValue("aInfo", ConstantVal.EMPTY) .addValue("stat", ConstantVal.ACTIVE) .addValue("cnclTask", ConstantVal.ZERO) .addValue("asgnNbr", ConstantVal.EMPTY) .addValue("priInd", ConstantVal.ZERO) .addValue("ovlpMatchNbr", ConstantVal.EMPTY) .addValue("attchIds", ConstantVal.EMPTY) .addValue("aType", ConstantVal.EMPTY) .addValue("lInd", ConstantVal.ZERO) .addValue("pAsgn", ConstantVal.ZERO) .addValue("rId", ConstantVal.EMPTY) .addValue("bInd", ConstantVal.EMPTY) .addValue("createDtTm", new Timestamp((new Date()).getTime())) .addValue("updatedDtTm", ConstantVal.EMPTY); int nb = namedParameterJdbcTemplate.update(insertRecords, parameters, keyHolder, new String[] { "ID" });
SQL配置(beans.xml):
<bean id="insertRecords" class="java.lang.String" scope="prototype"> <constructor-arg type="java.lang.String" value=" INSERT INTO XYZ ( ID, PACKAGE_ID, IS_ASGN, START_TM, END_TM, TYPE, NOTE, FDBK, S_CNT, A_CD, IS_AUTO, DFLT_START_TM, DFLT_END_TM, A_INFO, STAT, IS_CNCL_TASK, ASGN_NBR, PRI_ASGN_IND, OVLP_MATCH_NBR, A_IDS, ASGN_TYPE, LOCK_IND, P_ASGN, R_ID, B_IND, CREATED_DT_TM, UPDATED_DT_TM ) VALUES ( :Id, :packageId,:isAsgn,:startTm,:endTm,:type,:note,:fdbk,:sCnt,:aCd,:isAuto,:dfltStartTm,:dfltEndTm,:aInfo, :stat,:cnclTask,:asgnNbr,:priInd,:ovlpMatchNbr,:attchIds,:aType,:lInd,:pAsgn,:rId, :bInd,:createDtTm,:updatedDtTm) " /> </bean>
错误栈
java.lang.ArrayIndexOutOfBoundsException at oracle.jdbc.driver.OracleSql.computeBasicInfo(OracleSql.java:950) at oracle.jdbc.driver.OracleSql.getSqlKind(OracleSql.java:623) at oracle.jdbc.driver.OraclePreparedStatement.<init>(OraclePreparedStatement.java:1212) at oracle.jdbc.driver.T4CPreparedStatement.<init>(T4CPreparedStatement.java:28) at oracle.jdbc.driver.T4CDriverExtension.allocatePreparedStatement(T4CDriverExtension.java:68) at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:3140) at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:3042) at oracle.jdbc.driver.PhysicalConnection.prepareStatement(PhysicalConnection.java:6022) at oracle.jdbc.OracleConnectionWrapper.prepareStatement(OracleConnectionWrapper.java:679) at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.pmiPrepareStatement(WSJdbcConnection.java:5071) at com.ibm.ws.rsadapter.jdbc.WSJdbcConnection.prepareStatement(WSJdbcConnection.java:4946) at org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.createPreparedStatement(PreparedStatementCreatorFactory.java:231) at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:638) at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:943) at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.update(NamedParameterJdbcTemplate.java:344)
解决方案
这个错误通常是Oracle JDBC驱动在解析SQL语句或处理参数时出现的问题,以下是几个可行的排查和解决步骤:
1. 修复SQL语句中的占位符格式
你的SQL语句中部分占位符之间没有空格(比如:packageId,:isAsgn),虽然语法上合法,但旧版本的Oracle驱动可能在解析时出现索引越界问题。建议给所有占位符之间添加空格,同时格式化SQL提升可读性:
INSERT INTO XYZ ( ID, PACKAGE_ID, IS_ASGN, START_TM, END_TM, TYPE, NOTE, FDBK, S_CNT, A_CD, IS_AUTO, DFLT_START_TM, DFLT_END_TM, A_INFO, STAT, IS_CNCL_TASK, ASGN_NBR, PRI_ASGN_IND, OVLP_MATCH_NBR, A_IDS, ASGN_TYPE, LOCK_IND, P_ASGN, R_ID, B_IND, CREATED_DT_TM, UPDATED_DT_TM ) VALUES ( :Id, :packageId, :isAsgn, :startTm, :endTm, :type, :note, :fdbk, :sCnt, :aCd, :isAuto, :dfltStartTm, :dfltEndTm, :aInfo, :stat, :cnclTask, :asgnNbr, :priInd, :ovlpMatchNbr, :attchIds, :aType, :lInd, :pAsgn, :rId, :bInd, :createDtTm, :updatedDtTm )
2. 检查参数与数据库列的类型匹配
注意到你给updatedDtTm参数传入的是ConstantVal.EMPTY(推测是空字符串),但数据库列UPDATED_DT_TM是日期类型。Oracle的日期列无法接受空字符串,这会导致驱动解析时出错。应该传入null而非空字符串:
.addValue("updatedDtTm", null)
同时检查其他参数的类型,比如LOCK_IND、PRI_ASGN_IND等列如果是数字类型,确保传入的ConstantVal.ZERO是数字而非字符串。
3. 升级Oracle JDBC驱动版本
这个错误在Oracle JDBC驱动的旧版本(比如11g的某些版本)中是已知问题,升级到稳定的新版本(比如12.2.0.1或更高)可以解决这类解析bug。如果使用Maven,更新依赖:
<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>12.2.0.1</version> </dependency>
4. 验证KeyHolder的使用合理性
你在update方法中指定了keyHolder和new String[] { "ID" },但代码中你手动传入了ID的值(12345678)。如果ID不是自增列,不需要使用KeyHolder来获取生成的键,移除这两个参数试试:
int nb = namedParameterJdbcTemplate.update(insertRecords, parameters);
如果ID确实是自增列,确保数据库配置了自动生成策略,并且参数中不要手动传入Id的值。
内容的提问来源于stack exchange,提问作者KVNS_JavaLearner

