Prepared Statement + 업데이트를 위해 선택 + 기본 키 열에 Oracle 12c + ORA-01461
업데이트를 위해 선택 문을 실행한 다음 삽입 또는 업데이트를 실행하려고 할 때 이상한 문제가 발생합니다.ORA-01461 예외가 발생했습니다.이 문제는 최신 ojdbc 드라이버(12.1.0.2)를 사용하는 경우에만 발생하며 이전 드라이버(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();
}
}
}
}
주 메서드의 첫 번째 줄에 UUID 생성
UUID.randomUUID().toString();
36자 길이입니다.이 샘플 클래스를 실행하면 ORA-01461 오류가 발생하지만 위에서 언급한 라인을 다음으로 변경합니다.
UUID.randomUUID().toString().replaceAll("-", "");
32자 문자열이 올바르게 실행되고 행이 데이터베이스에 삽입됩니다.위 문자열이 저장된 "TEST_ID" 열은 VARCHAR2(40CHAR)이며 32 및 36자 문자열을 모두 수용할 수 있습니다.열의 길이를 더 큰 숫자로 늘린다고 해서 변경되는 것은 없습니다.
제 샘플 코드가 읽기 쉽고 이해하기 쉬웠으면 좋겠고 이 문제에 대한 해결책/설명을 기대하고 있습니다.
감사합니다!
데이터베이스 정보:
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 문자열 길이와 관련하여) 이 문제가 보이는 것보다 더 이상하다는 것을 나타내기 위해 동일한 데이터로 삽입 문을 실행하도록 약간 수정되었습니다.다음 샘플 코드는 최신 오라클 드라이버로 올바르게 실행됩니다.
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();
}
}
}
이는 12.1.0.2.0 jdbc 드라이버의 버그이며 이를 해결하기 위해 패치가 필요하기 때문에 Oracle에 SR을 열었습니다.
이 오류는 SQL 문에서 4000바이트보다 긴 varchar 변수를 사용하려고 시도할 때 발생합니다(4000바이트가 제한됨).
당신은 그것이 무엇인지 확인해야 합니다.uuid
변수에는 가능한 인코딩에 주의를 기울이는 내용이 포함되어 있습니다.
어쨌든 VARCHAR 데이터 유형과 같은 UUID를 저장하는 것은 좋은 생각이 아닙니다.
이 작업을 수행하기 위한 해결 방법은 다음과 같습니다.TEST_ID
데이터 형식VARCHAR2
로.CLOB
(아래 댓글에서 말씀하신 것처럼 PK 제거) 하지만 이것은 해결책이 아닙니다.
언급URL : https://stackoverflow.com/questions/34655888/preparedstatement-select-for-update-oracle-12c-ora-01461-in-primary-key-co
'programing' 카테고리의 다른 글
뮤텍스 잠금 스레드 (0) | 2023.07.26 |
---|---|
Python에서 예외를 포착하고 시도 블록을 계속합니다. (0) | 2023.07.26 |
SQL Developer 오류 Java 가상 시스템을 찾을 수 없습니다. (0) | 2023.07.26 |
CSV 파일 팬더를 읽을 때 열 이름 지정 (0) | 2023.07.26 |
SYS_OP_C2C 내부 변환으로 인한 Oracle SQL 실행 계획 변경 (0) | 2023.07.26 |