Mam problem z zapisaniem i odczytaniem znaków specjalnych, takich jak znak Euro (€), do właściwości LOB String w PostgreSQL 8.4 z Hibernate 3.6.10.Nie można zapisać znaku Euro we właściwości LOB String przy użyciu Hibernate/PostgreSQL
Wiem, że PostgreSQL zapewnia dwa różne sposoby przechowywania dużych obiektów znaków w kolumnie tabeli. Mogą być przechowywane bezpośrednio w tej kolumnie tabeli lub pośrednio w osobnej tabeli (faktycznie nazywa się to pg_largeobject). W tym drugim przypadku kolumna zawiera odniesienie (OID) do wiersza w pg_largeobject.
Domyślnym zachowaniem w Hibernate 3.6.10 jest pośrednie podejście OID. Możliwe jest jednak dodanie dodatkowej adnotacji @ org.hibernate.annotations.Type (type = "org.hibernate.type.TextType") do właściwości Lob, aby uzyskać zachowanie bezpośredniego przechowywania.
Oba podejścia działają dobrze, z wyjątkiem momentu, w którym chcę pracować ze znakami specjalnymi, takimi jak znak Euro (€). W takim przypadku mechanizm bezpośredniego zapisu działa, ale pośredni mechanizm magazynowania zostaje przerwany.
Chciałbym to zademonstrować na przykładzie. Stworzyłem jednostkę testową z 2 właściwościami @Lob. Jeden następuje bezpośredni zasady przechowywania, drugi przechowywanie pośrednie:
@Basic
@Lob
@Column(name = "CLOB_VALUE_INDIRECT_STORAGE", length = 2147483647)
public String getClobValueIndirectStorage()
i
@Basic
@Lob
@org.hibernate.annotations.Type(type="org.hibernate.type.TextType")
@Column(name = "CLOB_VALUE_DIRECT_STORAGE", length = 2147483647)
public String getClobValueDirectStorage()
Jeśli utworzyć podmiot, wypełnić zarówno właściwości ze znakiem Euro i następnie utrzymywać w kierunku bazy widzę następujące kiedy zrobić SELECT widzę
id | clob_value_direct_storage | clob_value_indirect_storage
----+---------------------------+----------------------------
6 | € | 910579
Gdybym wtedy kwerendy pg_largeobject tabeli widać:
loid | pageno | data
--------+--------+------
910579 | 0 | \254
Kolumna "data" obiektu pg_largeobject ma typ bytea, co oznacza, że informacje są przechowywane jako surowe bajty. Wyrażenie "\ 254" reprezentuje jeden pojedynczy bajt, a w UTF-8 oznacza znak "¬". Jest to dokładnie wartość, którą otrzymuję, gdy ładuję obiekt z bazy danych.
Znak Euro w UTF-8 składa się z 3 bajtów, więc spodziewałem kolumnie „dane”, aby mieć 3 bajty, a nie 1.
To nie tylko występować na znak Euro, ale dla wiele znaków specjalnych. Czy to jest problem w Hibernate? Lub sterownik JDBC? Czy jest sposób, w jaki mogę zmienić to zachowanie?
Dzięki z góry,
poważaniem,
Franck de Bruijn
Dlaczego używasz dużych obiektów w pierwszej kolejności? Po prostu użyj typu danych "text" dla tej kolumny. Nie ma potrzeby robienia bałaganu z 'bytea' lub dużymi obiektami, jeśli wszystko, co chcesz zapisać, to tekst. –
Może być wiele powodów, aby to zrobić. Nie wiem Zapewniam ramy dla innych użytkowników i chcę wspierać obie alternatywy. W starszych wersjach sterownika JDBC (lub Hibernate, nie jestem pewien) domyślnym zachowaniem było "bezpośrednie przechowywanie". Później zmieniono to na "pośrednie przechowywanie". Prawdopodobnie z jakiegoś dobrego powodu. –
Zastanowiłem się trochę nad tym i zacząłem się coraz bardziej zgadzać z a_horse_with_no_name. Po pierwsze, pośredni mechanizm magazynowania uniemożliwia korzystanie z tej kolumny w zapytaniu HQL, co jest wielką wadą. Pośredni mechanizm przechowywania ułatwia opcję przesyłania strumieniowego, dzięki czemu można przesyłać strumieniowo zawartość bezpośrednio z bazy danych do klienta (oszczędzając zużycie pamięci). Na pewno jest to poprawny argument dla obiektów BLOB, ale dla obiektów CLOB? W większości scenariuszy rozmiar rzeczywistych CLOB nie będzie tak duży, z pewnością nie w zakresie 1M lub więcej. Można to zrobić w pamięci. –