PreparedStatement + Select for update + Oracle 12c + 主键列中的 ORA-01461
PreparedStatement + Select for update + Oracle 12c + ORA-01461 in primary key column
我在尝试执行 select for update 语句然后执行插入或更新时遇到一个奇怪的问题。我得到一个 ORA-01461 exception. This happens only when using the latest ojdbc driver (12.1.0.2), while in the older one it works fine (12.1.0.1).
更具体地说,最新的驱动程序似乎对主键字符长度有某种限制(限制为 32 个字符),尽管相应的列被声明为超过 32 个字符。复制问题的示例代码如下:
CREATE TABLE "TEST_TABLE" (
"TEST_ID" VARCHAR2(40 CHAR) NOT NULL ENABLE,
"TEST_COMMENT" VARCHAR2(200 CHAR),
CONSTRAINT "TEST_TABLE_PK" PRIMARY KEY ("TEST_ID")
);
还有一些 java:
public class DemoUpdatableResultSet {
private static final String DB_URL = "jdbc:oracle:thin:@xxxx:1521/xxxxx";
private static final String DB_USER = "xxx";
private static final String DB_PASS = "xxx";
public static Connection getConnection() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
return conn;
}
public static void main(String[] args) {
final String uuid = UUID.randomUUID().toString();
ResultSet rs = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String query = "SELECT t.* FROM TEST_TABLE t WHERE t.TEST_ID=? FOR UPDATE";
pstmt = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
pstmt.setString(1, uuid); // set input values
rs = pstmt.executeQuery(); // create an updatable ResultSet
// insert column values into the insert row.
rs.moveToInsertRow(); // moves cursor to the insert row
rs.updateString("TEST_ID", uuid); // updates the 2nd column
rs.updateString("TEST_COMMENT", "Comment for: " + uuid);
rs.insertRow();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
main方法的第一行创建了一个uuid
UUID.randomUUID().toString();
长度为 36 个字符。 运行 此示例 class 将产生 ORA-01461 错误,但将上述行更改为
UUID.randomUUID().toString().replaceAll("-", "");
生成 32 个字符的字符串将 运行 正确并将行插入数据库。请注意,保存上述字符串的 "TEST_ID" 列是 VARCHAR2(40 CHAR) 并且可以容纳 32 和 36 个字符的字符串。将列的长度增加到更大的数字不会改变任何内容。
我希望我的示例代码易于阅读和理解,我期待 solution/explanation 这个问题。
谢谢!
数据库信息:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
"CORE 12.1.0.2.0 Production"
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production
稍微修改为运行一个具有相同数据的插入语句,以表明这个问题比看起来更奇怪(关于 uuid 字符串长度)。以下示例代码使用最新的 oracle 驱动程序正确执行:
public static void main(String[] args) {
final String uuid = UUID.randomUUID().toString();
ResultSet rs = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String query = "INSERT INTO TEST_TABLE (TEST_ID, TEST_COMMENT) VALUES (?, ?)";
pstmt = conn.prepareStatement(query);
pstmt.setString(1, uuid); // set input values
pstmt.setString(2, "Comment for: " + uuid); // set input values
rs = pstmt.executeQuery();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
尝试在 SQL 语句中使用超过 4000 字节的 varchar 变量时发生此错误(4000 字节是限制)。
您应该检查 uuid
变量包含的内容,注意可能的编码。
无论如何,将 UUID 存储为 VARCHAR 数据类型并不是一个好主意。
使其工作的解决方法是将 TEST_ID
数据类型从 VARCHAR2
更改为 CLOB
(删除 PK,就像您在下面的评论中所说的那样)但这不是解决方案。
向 oracle 打开了一个 SR,因为这是 12.1.0.2.0 jdbc 驱动程序的一个错误,需要一个补丁来解决它。
我在尝试执行 select for update 语句然后执行插入或更新时遇到一个奇怪的问题。我得到一个 ORA-01461 exception. This happens only when using the latest ojdbc driver (12.1.0.2), while in the older one it works fine (12.1.0.1).
更具体地说,最新的驱动程序似乎对主键字符长度有某种限制(限制为 32 个字符),尽管相应的列被声明为超过 32 个字符。复制问题的示例代码如下:
CREATE TABLE "TEST_TABLE" (
"TEST_ID" VARCHAR2(40 CHAR) NOT NULL ENABLE,
"TEST_COMMENT" VARCHAR2(200 CHAR),
CONSTRAINT "TEST_TABLE_PK" PRIMARY KEY ("TEST_ID")
);
还有一些 java:
public class DemoUpdatableResultSet {
private static final String DB_URL = "jdbc:oracle:thin:@xxxx:1521/xxxxx";
private static final String DB_USER = "xxx";
private static final String DB_PASS = "xxx";
public static Connection getConnection() throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
return conn;
}
public static void main(String[] args) {
final String uuid = UUID.randomUUID().toString();
ResultSet rs = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String query = "SELECT t.* FROM TEST_TABLE t WHERE t.TEST_ID=? FOR UPDATE";
pstmt = conn.prepareStatement(query, ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
pstmt.setString(1, uuid); // set input values
rs = pstmt.executeQuery(); // create an updatable ResultSet
// insert column values into the insert row.
rs.moveToInsertRow(); // moves cursor to the insert row
rs.updateString("TEST_ID", uuid); // updates the 2nd column
rs.updateString("TEST_COMMENT", "Comment for: " + uuid);
rs.insertRow();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
main方法的第一行创建了一个uuid
UUID.randomUUID().toString();
长度为 36 个字符。 运行 此示例 class 将产生 ORA-01461 错误,但将上述行更改为
UUID.randomUUID().toString().replaceAll("-", "");
生成 32 个字符的字符串将 运行 正确并将行插入数据库。请注意,保存上述字符串的 "TEST_ID" 列是 VARCHAR2(40 CHAR) 并且可以容纳 32 和 36 个字符的字符串。将列的长度增加到更大的数字不会改变任何内容。
我希望我的示例代码易于阅读和理解,我期待 solution/explanation 这个问题。
谢谢!
数据库信息:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
"CORE 12.1.0.2.0 Production"
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production
稍微修改为运行一个具有相同数据的插入语句,以表明这个问题比看起来更奇怪(关于 uuid 字符串长度)。以下示例代码使用最新的 oracle 驱动程序正确执行:
public static void main(String[] args) {
final String uuid = UUID.randomUUID().toString();
ResultSet rs = null;
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = getConnection();
String query = "INSERT INTO TEST_TABLE (TEST_ID, TEST_COMMENT) VALUES (?, ?)";
pstmt = conn.prepareStatement(query);
pstmt.setString(1, uuid); // set input values
pstmt.setString(2, "Comment for: " + uuid); // set input values
rs = pstmt.executeQuery();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
尝试在 SQL 语句中使用超过 4000 字节的 varchar 变量时发生此错误(4000 字节是限制)。
您应该检查 uuid
变量包含的内容,注意可能的编码。
无论如何,将 UUID 存储为 VARCHAR 数据类型并不是一个好主意。
使其工作的解决方法是将 TEST_ID
数据类型从 VARCHAR2
更改为 CLOB
(删除 PK,就像您在下面的评论中所说的那样)但这不是解决方案。
向 oracle 打开了一个 SR,因为这是 12.1.0.2.0 jdbc 驱动程序的一个错误,需要一个补丁来解决它。