ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。ojdbc8版本23.2.0.0驱动BUG【已解决】

问题描述

JDK8使用ojdbc8驱动操作oracle11g数据库,使用JDBC复用 PreparedStatement 对象执行Insert操作时,报错java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值。,经测试发现,是预编译对象某个占位符号被赋值为NULL后,再次尝试赋值为2个汉字,执行时就会报错:

shell 复制代码
Caused by: java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值

	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:702)
	at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:608)
	at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1248)
	at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:1041)
	at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:443)
	at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:518)
	at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:251)
	at oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:1181)
	at oracle.jdbc.driver.OracleStatement.executeSQLStatement(OracleStatement.java:1571)
	at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1345)
	at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3728)
	at oracle.jdbc.driver.OraclePreparedStatement.executeLargeUpdate(OraclePreparedStatement.java:3905)
	at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3880)
	at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:993)
	at com.p6spy.engine.wrapper.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:94)
	at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeUpdate(DruidPooledPreparedStatement.java:241)

问题复现

测试表DDL

sql 复制代码
CREATE TABLE "TEST_TABLE" (
  "TEST_COLUMN" VARCHAR2(255 BYTE)
)

java代码

java 复制代码
   @Test
    public void testOracleChineseInsert() {
        try (Connection oracleConnection = getOracleConnection()) {
            Statement statement = oracleConnection.createStatement();
            statement.execute("truncate table TEST_TABLE");
            PreparedStatement preparedStatement = oracleConnection.prepareStatement("INSERT INTO TEST_TABLE VALUES (?)");
            List<String> list = new ArrayList<>();
            list.add("你好");
            list.add(null);
            list.add("你好");
            for (String data : list) {
                try {
                    preparedStatement.setString(1, data);
                    preparedStatement.executeUpdate();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

ORACLE数据库字符集

sql 复制代码
-- 查询字符集
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
-- 查询结果
NLS_CHARACTERSET	ZHS16GBK
NLS_NCHAR_CHARACTERSET	AL16UTF16

依赖版本

xml 复制代码
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>23.2.0.0</version>
</dependency>

执行结果

前两条记录能新增成功,第三条记录报错 ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值

解决办法

更换驱动版本后发现该BUG已被修复,更新驱动版本(推荐)

xml 复制代码
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>23.6.0.24.10</version>
</dependency>

或者代码中避免复用预编译对象,每个语句新建一个预编译对象(不推荐)

java 复制代码
   @Test
    public void testOracleChineseInsert() {
        try (Connection oracleConnection = getOracleConnection()) {
            Statement statement = oracleConnection.createStatement();
            statement.execute("truncate table TEST_TABLE");
            List<String> list = new ArrayList<>();
            list.add("你好");
            list.add(null);
            list.add("你好");
            for (String data : list) {
                try {
            PreparedStatement preparedStatement = oracleConnection.prepareStatement("INSERT INTO TEST_TABLE VALUES (?)");
                    preparedStatement.setString(1, data);
                    preparedStatement.executeUpdate();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
相关推荐
摇滚侠3 分钟前
全面掌握 PostgreSQL 关系型数据库,PostgreSQL 介绍,笔记02
数据库·笔记·postgresql
百锦再19 分钟前
国产数据库替代MongoDB的技术实践:金仓数据库赋能浙江省人民医院信息化建设新展望
java·开发语言·数据库·mongodb·架构·eclipse·maven
程序边界19 分钟前
MongoDB迁移到KES实战全纪录(下):性能优化与实践总结
数据库·mongodb·性能优化
武子康20 分钟前
Java-160 MongoDB副本集部署实战 单机三实例/多机同法 10 分钟起集群 + 选举/读写/回滚全流程
java·数据库·sql·mongodb·性能优化·系统架构·nosql
这儿有一堆花21 分钟前
使用 Actix-web 开发高性能 Web 服务
前端·数据库
与衫1 小时前
SQL 调试不再靠猜:Gudu SQL Omni 让血缘分析一键可视化
数据库·sql
ZZZKKKRTSAE1 小时前
MySQL一篇速通
数据库·mysql·1024程序员节
阿祥~1 小时前
windows 安装 Redis
数据库·redis·缓存
我是唐青枫2 小时前
C#.NET SqlKata 使用详解:优雅构建动态 SQL 查询
sql·c#·.net
21号 12 小时前
21.事务和锁(重点)
开发语言·数据库