Tôi gặp sự cố khi viết và đọc lại các ký tự đặc biệt như ký hiệu Euro (€) thành thuộc tính Chuỗi LOB trong PostgreSQL 8.4 với Hibernate 3.6.10.Không thể lưu trữ dấu Euro vào thuộc tính Chuỗi LOB với Hibernate/PostgreSQL
Điều tôi biết là PostgreSQL cung cấp hai cách riêng biệt để lưu trữ các đối tượng ký tự lớn trong một cột của bảng. Chúng có thể được lưu trữ trực tiếp vào cột bảng đó hoặc gián tiếp trong một bảng riêng biệt (nó thực sự được gọi là pg_largeobject). Trong trường hợp sau, cột chứa một tham chiếu (OID) đến hàng trong pg_largeobject.
Hành vi mặc định trong Hibernate 3.6.10 là cách tiếp cận OID gián tiếp. Tuy nhiên, có thể thêm chú thích bổ sung @ org.hibernate.annotations.Type (type = "org.hibernate.type.TextType") vào thuộc tính Lob để có được hành vi lưu trữ trực tiếp.
Cả hai phương pháp đều hoạt động tốt, ngoại trừ thời điểm tôi muốn làm việc với các ký tự đặc biệt như ký hiệu Euro (€). Trong trường hợp đó, cơ chế lưu trữ trực tiếp tiếp tục hoạt động, nhưng cơ chế lưu trữ gián tiếp bị gián đoạn.
Tôi muốn chứng minh điều đó bằng ví dụ. Tôi đã tạo một thực thể thử nghiệm với 2 thuộc tính @Lob. Một tuân theo nguyên tắc lưu trữ trực tiếp, khác lưu trữ gián tiếp:
@Basic
@Lob
@Column(name = "CLOB_VALUE_INDIRECT_STORAGE", length = 2147483647)
public String getClobValueIndirectStorage()
và
@Basic
@Lob
@org.hibernate.annotations.Type(type="org.hibernate.type.TextType")
@Column(name = "CLOB_VALUE_DIRECT_STORAGE", length = 2147483647)
public String getClobValueDirectStorage()
Nếu tôi tạo ra một tổ chức nào, cư cả khách sạn với dấu hiệu Euro và sau đó kéo dài nó đối với cơ sở dữ liệu tôi thấy sau khi tôi làm một SELECT tôi thấy
id | clob_value_direct_storage | clob_value_indirect_storage
----+---------------------------+----------------------------
6 | € | 910579
Nếu tôi sau đó truy vấn pg_largeobject bảng tôi thấy:
loid | pageno | data
--------+--------+------
910579 | 0 | \254
Cột 'dữ liệu' của pg_largeobject thuộc loại bytea, có nghĩa là thông tin được lưu trữ dưới dạng byte thô. Biểu thức '\ 254' đại diện cho một byte đơn và trong UTF-8 biểu diễn ký tự '¬'. Đây chính là giá trị mà tôi lấy lại khi tôi nạp thực thể trở lại từ cơ sở dữ liệu.
Dấu hiệu Euro trong UTF-8 gồm 3 byte, vì vậy tôi dự kiến sẽ có cột 'dữ liệu' có 3 byte và không 1.
này không chỉ xảy ra đối với các dấu hiệu Euro, nhưng đối với nhiều nhân vật đặc biệt. Đây có phải là một vấn đề trong Hibernate? Hoặc trình điều khiển JDBC? Có cách nào tôi có thể tinh chỉnh hành vi này không?
Cảm ơn trước,
Trân trọng!
Franck de Bruijn
Tại sao bạn sử dụng các đối tượng lớn ngay từ đầu? Chỉ cần sử dụng kiểu dữ liệu 'văn bản' cho cột đó. Không cần phải xáo trộn xung quanh với 'bytea' hoặc các đối tượng lớn nếu tất cả những gì bạn muốn lưu trữ là văn bản. –
Có thể có nhiều lý do để làm như vậy. Tôi không biết. Tôi cung cấp một khuôn khổ cho những người dùng khác để sử dụng và tôi muốn hỗ trợ cả hai lựa chọn thay thế. Trong các phiên bản cũ của trình điều khiển JDBC (hoặc Hibernate, tôi không chắc chắn) hành vi mặc định là 'lưu trữ trực tiếp'. Sau đó thay đổi thành 'lưu trữ gián tiếp'. Có lẽ vì một số lý do chính đáng. –
Tôi suy nghĩ về điều này nhiều hơn một chút và tôi thực sự bắt đầu đồng ý nhiều hơn và nhiều hơn nữa với a_horse_with_no_name. Trước tiên, cơ chế lưu trữ gián tiếp ngăn cản bạn sử dụng cột này trong truy vấn HQL, đây là một bất lợi lớn. Cơ chế lưu trữ gián tiếp tạo điều kiện cho tùy chọn phát trực tuyến, để bạn có thể truyền trực tiếp nội dung từ cơ sở dữ liệu đến ứng dụng khách (tiết kiệm dung lượng bộ nhớ). Để chắc chắn đây là một đối số hợp lệ cho BLOB, nhưng đối với các CLOB? Trong hầu hết các kịch bản, kích thước của CLOB thực tế sẽ không lớn, chắc chắn không nằm trong phạm vi từ 1 triệu trở lên. Điều này có thể được xử lý trong bộ nhớ. –