通过JDBC执行长INSERT语句时遇ORA-01704错误的问题
解决Oracle ORA-01704: string literal too long 错误的方案
这个问题我太熟悉了——Oracle的ORA-01704错误几乎都是因为字符串字面量超过了4000字符的限制,而SQL Developer之所以能正常执行,是因为它偷偷帮你做了绑定变量的转换工作😉
问题根源
Oracle的SQL语法有个硬性限制:直接写在SQL语句里的单引号包裹的字符串(字面量)最大长度只能是4000字符。你的XML字符串超过10K,直接把它硬编码在INSERT语句里传给JDBC时,数据库会把整个SQL当作语法解析,自然触发这个错误。而SQL Developer在执行脚本时,会自动识别超长的字面量,将其转换成绑定变量的形式传递,绕开了字面量长度限制,所以不会报错。
解决方案:必须用绑定变量
虽然你提到有需求限制,但这是解决这个问题的唯一可行办法。我们需要修改代码,把INSERT语句中的硬编码值替换成占位符?,通过PreparedStatement的参数传递方式传入大字符串。以下是针对你现有代码的修改方案:
1. 修改restoreFile方法,拆分SQL模板与参数
假设你的备份文件中INSERT语句格式规范(比如INSERT INTO table(col) VALUES ('超大XML内容')),我们可以通过字符串处理提取SQL模板和参数值:
public void restoreFile(File f) throws Exception { LineIterator it = FileUtils.lineIterator(f, "UTF-8"); try { while (it.hasNext()) { String insertStatement = it.nextLine(); if (!insertStatement.startsWith("--") && !insertStatement.isEmpty()) { // 去掉末尾的分号 insertStatement = insertStatement.replace(";", ""); // 拆分SQL模板和参数(适配单值INSERT场景) int valuesStart = insertStatement.indexOf("VALUES('"); if (valuesStart != -1) { // 构建带占位符的SQL模板 String sqlTemplate = insertStatement.substring(0, valuesStart + 7) + "?" + insertStatement.substring(insertStatement.lastIndexOf("')")); // 提取参数值,注意还原备份文件中转义的单引号('' → ') String value = insertStatement.substring(valuesStart + 8, insertStatement.lastIndexOf("'")) .replace("''", "'"); // 调用带参数的执行方法 executeSqlStatementWithParam(sqlTemplate, value); } else { // 处理多列或格式特殊的INSERT,仍用原方法执行(适合短字符串场景) executeSqlStatement(insertStatement); } } } } finally { it.close(); } }
2. 添加带参数的SQL执行方法
// 保留原无参数方法,兼容短字符串场景 public void executeSqlStatement(String sqlStatement) throws Exception { getJdbcTemplate().update(sqlStatement); } // 新增带绑定变量的执行方法 public void executeSqlStatementWithParam(String sqlTemplate, String param) throws Exception { getJdbcTemplate().update(connection -> { PreparedStatement stmt = connection.prepareStatement(sqlTemplate); // 用setString传递大字符串,绕过字面量限制 stmt.setString(1, param); return stmt; }); }
进阶优化(多列INSERT场景)
如果你的备份文件中有多列的INSERT语句(比如INSERT INTO table(col1, col2) VALUES ('val1', 'val2')),建议使用SQL解析库(比如Apache Commons SQL Parser)来拆分SQL和参数,避免自己写的字符串处理逻辑出现漏洞。
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

