Mam aplikację używającą hibernacji 3.1 i adnotacji JPA. Ma kilka obiektów z atrybutami byte [] (o rozmiarze 1k - 200k). Używa adnotacji JPA @Lob, a hibernacja 3.1 może je dobrze odczytać we wszystkich głównych bazach danych - wydaje się, że ukrywa osobliwości dostawcy JDBC Blob (tak jak powinno).
@Entity
public class ConfigAttribute {
@Lob
public byte[] getValueBuffer() {
return m_valueBuffer;
}
}
Musieliśmy uaktualnić do wersji 3.5, kiedy odkryliśmy, że hibernacja 3.5 przerywa (i nie naprawi) tej kombinacji adnotacji w postgresql (bez obejścia). Jak dotąd nie znalazłem wyraźnej poprawki, ale zauważyłem, że jeśli po prostu usunę @Lob, używa on bajtu typu postgresql (który działa, ale tylko na postgres).
annotation postgres oracle works on
-------------------------------------------------------------
byte[] + @Lob oid blob oracle
byte[] bytea raw(255) postgresql
byte[] + @Type(PBA) oid blob oracle
byte[] + @Type(BT) bytea blob postgresql
once you use @Type, @Lob seems to not be relevant
note: oracle seems to have deprecated the "raw" type since 8i.
Szukam sposobu, aby mieć jedną klasę z adnotacjami (z właściwością blob), która jest przenośna w głównych bazach danych.
- Jaki jest przenośny sposób dodawania adnotacji do właściwości byte []?
- Czy zostało to naprawione w jakiejś najnowszej wersji hibernacji?
Aktualizacja: po przeczytaniu tego bloga w końcu odkryłem, jakie było pierwotne obejście problemu z JIRA: Najwyraźniej powinieneś porzucić @Lob i dodać adnotację do właściwości jako:
@Type(type="org.hibernate.type.PrimitiveByteArrayBlobType")
byte[] getValueBuffer() {...
Jednak to nie działa dla mnie - nadal otrzymuję identyfikatory OID zamiast bajtów; to jednak zadziałało dla autora wydania JIRA, który wydawał się chcieć oid.
Po odpowiedzi od A. Garcii, wypróbowałem następnie tę kombinację, która faktycznie działa na postgresql, ale nie na Oracle.
@Type(type="org.hibernate.type.BinaryType")
byte[] getValueBuffer() {...
To, co naprawdę muszę zrobić, to kontrolować, które @ org.hibernate.annotations.Type kombinację (@Lob + bajt [] zostanie zmapowane) do (na postgresql).
Oto fragment z 3.5.5.Final z MaterializedBlobType (sql type Blob). Według bloga Steve'a, postgresql chce, abyś używał strumieni dla bajtów (nie pytaj mnie dlaczego) i niestandardowego typu Bloba postgresql dla oids. Zauważ również, że użycie setBytes () na JDBC jest również dla bytea (z wcześniejszych doświadczeń). To wyjaśnia, dlaczego strumienie użycia nie mają wpływu, obie przyjmują „bajt”.
public void set(PreparedStatement st, Object value, int index) {
byte[] internalValue = toInternalFormat( value );
if ( Environment.useStreamsForBinary() ) {
// use streams = true
st.setBinaryStream( index,
new ByteArrayInputStream( internalValue ), internalValue.length );
}
else {
// use streams = false
st.setBytes( index, internalValue );
}
}
To skutkuje:
ERROR: column "signature" is of type oid but expression is of type bytea
Aktualizacja Kolejne logiczne pytanie brzmi: „dlaczego po prostu nie zmienić ręcznie definicji tabeli na bajtowe” i zachować (@Lob + bajt [])? To nie praca, DOPÓKI próbie zapisania null byte []. Który sterownik postgreSQL uważa za wyrażenie typu OID, a typ kolumny to bajt - dzieje się tak, ponieważ hibernacja (słusznie) wywołuje JDBC.setNull () zamiast JDBC.setBytes (null), czego oczekuje sterownik PG.
ERROR: column "signature" is of type bytea but expression is of type oid
System typów w hibernacji jest obecnie w toku (zgodnie z komentarzem do wycofania 3.5.5). W rzeczywistości tak duża część kodu 3.5.5 jest przestarzała, że trudno jest wiedzieć, na co zwrócić uwagę podczas tworzenia podklas PostgreSQLDialect).
AFAKT, Types.BLOB / 'oid' w postgresql powinny być odwzorowane na jakiś niestandardowy typ, który wykorzystuje dostęp JDBC w stylu OID (tj. Obiekt PostgresqlBlobType i NOT MaterializedBlobType). Nigdy tak naprawdę nie korzystałem z Blobów z postgresql, ale wiem, że bytea po prostu działa tak, jak się spodziewałem.
Obecnie patrzę na wyjątek BatchUpdateException - możliwe, że sterownik nie obsługuje przetwarzania wsadowego.
Świetny cytat z 2004 roku: „Podsumowując moje wędrówki, powiedziałbym, że powinniśmy poczekać, aż sterownik JDBC poprawnie wykona LOB przed zmianą Hibernate”.
Bibliografia:
- https://forum.hibernate.org/viewtopic.php?p=2393203
- https://forum.hibernate.org/viewtopic.php?p=2435174
- http://hibernate.atlassian.net/browse/HHH-4617
- http://postgresql.1045698.n5.nabble.com/Migration-to-Hibernate-3-5-final-td2175339.html
- https://jira.springframework.org/browse/SPR-2318
- https://forums.hibernate.org/viewtopic.php?p=2203382&sid=b526a17d9cf60a80f13d40cf8082aafd
- http://virgo47.wordpress.com/2008/06/13/jpa-postgresql-and-bytea-vs-oid-type/
Odpowiedzi:
To zależy od tego, czego chcesz. JPA może utrwalać bez adnotacji
byte[]
. Ze specyfikacji JPA 2.0:A Hibernate mapuje go „domyślnie” na SQL
VARBINARY
(lub SQL wLONGVARBINARY
zależności odColumn
rozmiaru?), Który PostgreSQL obsługuje z rozszerzeniembytea
.Ale jeśli chcesz,
byte[]
aby był przechowywany w dużym obiekcie , powinieneś użyć pliku@Lob
. Ze specyfikacji:Hibernate zamapuje go na SQL
BLOB
obsługiwany przez PostgreSQL z rozszerzeniemoid
.Cóż, problem polega na tym, że nie wiem dokładnie, na czym polega problem. Ale mogę przynajmniej powiedzieć, że nic się nie zmieniło od 3.5.0-Beta-2 (czyli tam, gdzie wprowadzono zmianę) w gałęzi 3.5.x.
Ale moje rozumienie problemów takich jak HHH-4876 , HHH-4617 oraz PostgreSQL i BLOBs (wspomniane w javadoc w
PostgreSQLDialect
) jest takie, że powinieneś ustawić następującą właściwośćjeśli chcesz używać
oid
tj.byte[]
z@Lob
(co rozumiem, ponieważVARBINARY
nie jest to, czego chcesz w przypadku Oracle). Próbowałeś tego?Alternatywnie, HHH-4876 sugeruje użycie przestarzałego,
PrimitiveByteArrayBlobType
aby uzyskać stare zachowanie (przed Hibernate 3.5).Bibliografia
Zasoby
źródło
hibernate.jdbc.use_streams_for_binary=false
również? (zamierzam teraz sprawdzić, co powiedział Steve).Oto, co mówi Oreilly Enterprise JavaBeans 3.0
Oto kod źródłowy PostgreSQLDialect
Więc co możesz zrobić
Zastąp PostgreSQLDialect w następujący sposób
Teraz po prostu zdefiniuj swój własny dialekt
I użyj przenośnej adnotacji JPA @Lob
AKTUALIZACJA
Tutaj został wydobyty tutaj
...
co można wyjaśnić tutaj
...
Interesujące jest to, że kiedy mapuje Types.BOLB jako bajt (patrz CustomPostgreSQLDialect), otrzymuje
podczas wstawiania lub aktualizacji
źródło
Używam Hibernate 4.2.7.SP1 z Postgres 9.3 i działa dla mnie:
ponieważ Oracle nie ma z tym problemu, a dla Postgres używam niestandardowego dialektu:
Zaletą tego rozwiązania jest to, że mogę utrzymać słoiki w stanie hibernacji nietknięte.
Więcej informacji o problemach ze zgodnością Postgres / Oracle z Hibernate można znaleźć w moim poście na blogu .
źródło
Wreszcie udało mi się to. Rozwija się na rozwiązaniu A.Garcia, jednak ponieważ problem leży w hibernacji typu MaterializedBlob, samo mapowanie Blob> bajt nie jest wystarczające, potrzebujemy zamiennika dla MaterializedBlobType, który działa z hibernacją zepsutą obsługą blobów. Ta implementacja działa tylko z byteą, ale może facet z JIRA, który chciał OID, mógłby wnieść implementację OID.
Niestety zastępowanie tych typów w czasie wykonywania jest uciążliwe, ponieważ powinny one być częścią Dialektu. Gdyby tylko to rozszerzenie JIRA trafiło do 3.6, byłoby to możliwe.
Większość z nich może być prawdopodobnie statyczna (czy getBinder () naprawdę potrzebuje nowej instancji?), Ale tak naprawdę nie rozumiem wewnętrznej hibernacji, więc jest to głównie kopiowanie + wklejanie + modyfikowanie.
źródło
naprawiłem mój problem, dodając adnotację @Lob, która utworzy bajt [] w Oracle jako obiekt blob, ale ta adnotacja utworzy pole jako oid, które nie działa poprawnie. Aby bajt [] został utworzony jako bajt, zrobiłem klient Dialect dla postgres jak poniżej
Należy również nadpisać parametr dla dialektu
spring.jpa.properties.hibernate.dialect = com.ntg.common.DBCompatibilityHelper.PostgreSQLDialectCustom
więcej podpowiedzi można ją znaleźć: https://dzone.com/articles/postgres-and-oracle
źródło
Udało mi się to dzięki zastąpieniu adnotacji plikiem XML dla Postgres. Adnotacje są zachowywane dla Oracle. Moim zdaniem w tym przypadku najlepiej byłoby zastąpić mapowanie tego problemu - część z mapowaniem XML. Możemy przesłonić pojedyncze / wiele jednostek za pomocą mapowania XML. Więc użylibyśmy adnotacji dla naszej głównie obsługiwanej bazy danych i pliku xml dla każdej innej bazy danych.
Uwaga: musimy tylko zastąpić jedną klasę, więc nie jest to wielka sprawa. Przeczytaj więcej z mojego przykładu Przykład zastąpienia adnotacji za pomocą XML
źródło
Na Postgres @Lob łamie byte [], gdy próbuje zapisać go jako oid, a dla String również występuje ten sam problem. Poniższy kod psuje się na postgresach, co działa dobrze na oracle.
i
Aby naprawić powyższy postgres, poniżej napisałem niestandardowy hibernate.dialect
Teraz skonfiguruj niestandardowy dialekt w trybie hibernacji
XYZ to nazwa pakietu.
Teraz działa dobrze. UWAGA - Moja wersja Hibernate - 5.2.8. Ostateczna wersja Postgres - 9.6.3
źródło
Dzięki Justin, Pascal za poprowadzenie mnie we właściwym kierunku. Miałem również ten sam problem z Hibernate 3.5.3. Wasze badania i wskazówki dotyczące odpowiednich zajęć pomogły mi zidentyfikować problem i naprawić.
Z korzyścią dla tych, którzy wciąż tkwią w Hibernate 3.5 i używają kombinacji oid + byte [] + @LoB, oto co zrobiłem, aby rozwiązać problem.
Utworzyłem niestandardowy typ BlobType rozszerzający MaterializedBlobType i nadpisując metody set i get z dostępem w stylu oid.
Zarejestruj CustomBlobType w Hibernate. Oto, co zrobiłem, aby to osiągnąć.
źródło