Tại sao Oracle sử dụng độ dài byte khác với java cho chipmunk ký tự unicode bổ sung?


8

Tôi có mã java cắt xén một chuỗi UTF-8 theo kích thước của cột Oracle (11.2.0.4.0) của tôi, kết quả là gây ra lỗi vì java và Oracle xem chuỗi này có độ dài byte khác nhau. Tôi đã xác minh NLS_CHARACTERSETtham số của mình trong Oracle là 'UTF8'.

Tôi đã viết một bài kiểm tra minh họa vấn đề của mình dưới đây bằng biểu tượng cảm xúc chipmunk unicode ()

public void test() throws UnsupportedEncodingException, SQLException {
    String squirrel = "\uD83D\uDC3F\uFE0F";
    int squirrelByteLength = squirrel.getBytes("UTF-8").length; //this is 7
    Connection connection = dataSource.getConnection();

    connection.prepareStatement("drop table temp").execute();

    connection.prepareStatement("create table temp (foo varchar2(" + String.valueOf(squirrelByteLength) + "))").execute();

    PreparedStatement statement = connection.prepareStatement("insert into temp (foo) values (?)");
    statement.setString(1, squirrel);
    statement.executeUpdate();
}

Điều này không thành công ở dòng cuối cùng của bài kiểm tra với thông báo sau:

ORA-12899: giá trị quá lớn đối với cột
"MYSCHema". "TEMP". "FOO" (thực tế: 9, tối đa: 7)

Các thiết lập NLS_LENGTH_SEMANTICSBYTE. Thật không may, tôi không thể thay đổi điều này vì nó là một hệ thống cũ. Tôi không quan tâm đến việc tăng kích thước cột, đáng tin cậy là có thể dự đoán kích thước Oracle của một chuỗi.


Đáng buồn là tôi thấy các báo cáo mâu thuẫn trên internet về việc nên có bao nhiêu byte. Một số nói 7, một số nói 8, một số nói 12 (???). Điều gì xảy ra nếu bạn khai báo trường Oracle là 8 thay vì 7. Nó có hoạt động không? Tôi nhận ra rằng không trả lời rõ ràng câu hỏi của bạn về lý do tại sao nhưng nó có thể đưa ra một số câu trả lời cho bạn.
jcolebrand

Câu trả lời:


3

Điều gì sau đây là suy đoán của tôi.

Các Java Stringđược thể hiện bên trong bằng cách sử dụng mã hóa UTF-16 . Khi bạn getBytes("UTF-8")chuyển đổi Java giữa hai mã hóa và bạn có thể sử dụng nền tảng Java cập nhật.

Khi bạn cố lưu trữ Java Stringtrong cơ sở dữ liệu, Oracle cũng thực hiện chuyển đổi giữa UTF-16 gốc Java và bộ ký tự cơ sở dữ liệu được xác định bởi NLS_CHARACTERSET.

Ký tự chipmunk đã được phê duyệt là một phần của tiêu chuẩn Unicode năm 2014 (theo trang bạn đã liên kết), trong khi bản phát hành mới nhất của Oracle 11g rel.2 đã được xuất bản vào năm 2013 .

Mọi người có thể cho rằng Oracle sử dụng thuật toán chuyển đổi ký tự khác hoặc lỗi thời, do đó, biểu diễn byte của 🐿️) trên máy chủ (dài 9 byte) khác với những gì getBytes()trả về trên máy khách (7 byte).

Tôi đoán để giải quyết vấn đề này, bạn có thể nâng cấp máy chủ Oracle của mình hoặc sử dụng UTF-16 làm bộ ký tự cơ sở dữ liệu.


Điều đó đã giải quyết vấn đề. Lời tiên tri của tôi 11g đã sử dụng jdk 1.6.0_141 trong khi phiên bản 12 đang sử dụng jdk 1.8.0_121
agradl

3
Vui lòng đánh dấu câu hỏi là đã trả lời để người tiếp theo biết điều này có hiệu quả :)
jcolebrand

Tôi đã nói quá sớm, tôi đang điều tra thêm để xác nhận sự nghi ngờ của mình - nó không liên quan đến phiên bản tiên tri ... hãy theo dõi
agradl

1

Vấn đề là với xử lý của Oracle ký tự unicode bổ sung khi NLS_LENGTH_SEMANTICSUTF8.

Từ các tài liệu (nhấn mạnh thêm).

Bộ ký tự UTF8 mã hóa các ký tự theo một, hai hoặc ba byte. Nó dành cho các nền tảng dựa trên ASCII.

Các ký tự bổ sung được chèn vào cơ sở dữ liệu UTF8 không làm hỏng dữ liệu trong cơ sở dữ liệu. Một ký tự bổ sung được coi là hai ký tự do người dùng xác định, chiếm 6 byte. Oracle khuyên bạn nên chuyển sang AL32UTF8 để được hỗ trợ đầy đủ các ký tự bổ sung trong bộ ký tự cơ sở dữ liệu.

Ngoài ra, điểm mã cuối cùng trong chuỗi sóc là một bộ chọn biến thể và tùy chọn. Tôi đã thấy điều này bằng cách sử dụng một thanh tra ký tự unicode

Sau khi thay đổi NLS_CHARACTERSETtham số của cơ sở dữ liệu để AL32UTF8kiểm tra thông qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.