2016-01-07 16 views
13

Tôi có vấn đề lạ khi cố gắng thực thi chọn câu lệnh cập nhật và sau đó thực hiện sau đó chèn hoặc cập nhật. Tôi nhận được một ngoại lệ ORA-01461. Điều này chỉ xảy ra khi sử dụng trình điều khiển ojdbc mới nhất (12.1.0.2), trong khi ở chế độ cũ hơn, nó hoạt động tốt (12.1.0.1).PreparedStatement + Chọn để cập nhật + Oracle 12c + ORA-01461 trong cột khóa chính

Cụ thể hơn, trình điều khiển mới nhất dường như có một số giới hạn trong độ dài ký tự chính (giới hạn 32 ký tự) mặc dù cột tương ứng được khai báo hơn 32 ký tự. mẫu mã để tái tạo các vấn đề như sau:

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") 
); 

Và một số 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(); 
     } 
    } 
    } 
} 

Dòng đầu tiên của phương pháp chính tạo ra một uuid

UUID.randomUUID().toString(); 

đó là dài 36 ký tự. Chạy lớp mẫu này sẽ tạo ra một lỗi ORA-01.461, nhưng thay đổi dòng nêu trên để

UUID.randomUUID().toString().replaceAll("-", ""); 

trong đó sản lượng đến 32 ký tự chuỗi sẽ chạy một cách chính xác và chèn hàng trong cơ sở dữ liệu. Lưu ý rằng cột "TEST_ID" trong đó chuỗi trên được lưu là VARCHAR2 (40 CHAR) và có thể chứa cả hai chuỗi ký tự 32 và 36. Việc tăng chiều dài của cột lên những con số lớn hơn sẽ không thay đổi gì cả.

Tôi hy vọng mã mẫu của tôi dễ đọc và dễ hiểu và tôi mong chờ giải pháp/giải thích cho vấn đề này.

Cảm ơn!

Cơ sở dữ liệu Thông tin:

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 

Modified hơi để chạy một tuyên bố chèn với cùng một dữ liệu để chứng minh rằng vấn đề này là kỳ lạ hơn có vẻ như (về độ dài chuỗi uuid). Mẫu mã sau đây thực hiện một cách chính xác với trình điều khiển oracle mới nhất:

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(); 
     } 
    } 
    } 
+0

Xin chào, đã chỉnh sửa bài đăng đầu tiên của tôi và thêm thông tin cơ sở dữ liệu. Cảm ơn! – pleft

+0

Bạn có thể thử thay thế ký hiệu gạch nối bằng một ký tự khác (ví dụ '0' hoặc' a') thay vì chuỗi rỗng? Chỉ cần hiểu nếu vấn đề thực sự là kích thước ... Điều gì sẽ xảy ra? –

+0

Chắc chắn, chỉ cần thử nó, cùng một lỗi xảy ra ORA-01461, xin vui lòng xem chỉnh sửa của tôi với chức năng chính mới mà không chèn. – pleft

Trả lời

3

Đã mở SR thành oracle vì đây là lỗi của trình điều khiển jdbc 12.1.0.2.0 và cần bản vá để giải quyết.

+1

Chỉ để tham khảo trong tương lai, số lỗi là [Bug 22385253: RESULTSET.INSERTROW METHOD WITH JDBC 12.1.0.2.0 M ORI ORA-1461] (https://support.oracle.com/epmos/faces/BugDisplay?id=22385253) – gvenzl

+0

@gvenzl có cảm ơn vì đã lưu ý điều này! – pleft

-2

Lỗi này xảy ra cố gắng sử dụng một biến varchar dài hơn 4000 byte trong một câu lệnh SQL (4000 byte là giới hạn).

Bạn nên kiểm tra biến số uuid chứa sự chú ý đến mã hóa có thể.

Dù sao lưu trữ UUID như kiểu dữ liệu VARCHAR không phải là ý hay.

Cách giải quyết để làm cho nó làm việc có thể được thay đổi TEST_ID datatype VARCHAR2-CLOB (loại bỏ các PK như bạn nói trong bình luận dưới đây) nhưng đây không phải là giải pháp.

+1

Giải pháp của bạn không hoạt động. Bạn đã thực sự thử nó chưa? – yannisf

+0

@yannisf Không kể từ khi tôi đang trên điện thoại di động bây giờ nhưng trong quá khứ tôi đã nhận được cùng một vấn đề. Bạn đã cố gắng thay đổi kiểu dữ liệu trong 'VARBINARY (36)'? Kết quả có giống nhau không? –

+0

@ Satoshi Kouno: Câu trả lời của bạn là hiển nhiên nhất, nhưng xin lỗi, đây không phải là trường hợp. uuid chính xác là 36 ký tự, nếu bạn chạy một câu lệnh chèn với cùng một dữ liệu trong SQL Developer thì hàng được chèn vào không có lỗi. Và trong bài viết đầu tiên của tôi, tôi đề cập rằng nếu bạn cắt 4 ký tự từ uuid thì mã mẫu sẽ chèn hàng chính xác. – pleft

Các vấn đề liên quan