2012-10-26 3 views
6

Wir verwenden Hibernate als JPA-Provider und wir haben eine Klasse mit einem großen Objektfeld markiert mitorg.hibernate.type.TextType und Oracle

@Lob 
@Type(type = "org.hibernate.type.TextType") 
private String someString; 

Die Säule als

SOMESTRING   LONG()    
erstellt

Dies funktioniert einwandfrei mit PostgreSQL und MySQL. Mit Oracle, wenn das Objekt

entityManager.persist(object); 

beibehalten wird, erhalten wir eine org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update Ausnahme.

die @Type(type = "org.hibernate.type.TextType") Anmerkung Das Entfernen wird das Problem mit Oracle lösen, sondern führt eine Codierung Problem mit PostgreSQL beschrieben, wie in Cannot store Euro-sign into LOB String property with Hibernate/PostgreSQL

Ich mag würde wissen, wie ein großes Textfeld zu definieren, so dass out-Programm sowohl PostgreSQL arbeitet und Orakel. Eine reine JPA-Lösung wäre optimal, aber auch eine Hibernate-spezifische Lösung.

Edit:

Die wirkliche Ausnahme:

java.sql.BatchUpdateException: ORA-22295: cannot bind more than 4000 bytes data to LOB and LONG columns in 1 statement 

Nun ist die Ausnahme, die ich verpasst erklärt das Problem und in der Tat das Objekt ich persistierenden bin mehr als dann die große Zeichenfolge (mindestens eine lange DBID).

+0

Batch-Update konnte nicht ausgeführt werden, bedeutet nur, dass beim Übernehmen der Updates ein Fehler aufgetreten ist. Normalerweise gibt es eine konkretere Fehlermeldung in der Stack-Trace. Bitte posten Sie den kompletten Stack-Trace. – Johanna

+0

Nur um sicher zu gehen, dass ich dem Problem folge. Das Entfernen von '@ Type' (was ist die beabsichtigte richtige Lösung hier übrigens) ist problematisch wegen der nicht verstaatlichten Charakterunterstützung? Aka, mit Clob anstelle von NClob? –

+0

@SteveEbersole Ja, aber ich merke erst jetzt, dass das Entfernen der '@ Type' Annotation keine Auswirkung auf PostgreSQL hat (in beiden Fällen wird eine TEXT-Spalte erstellt). – Matteo

Antwort

1

Ich hatte eine similar problem und der einzige Weg war, den Oracle-Dialekt zu erweitern/anpassen.

+0

Erweitern Sie es wie, bitte geben Sie eine anständige Antwort! –

+0

@AndersMetnik Wenn Sie zu der verknüpften Frage gehen, sehen Sie den bereitgestellten Code. – mindas

1

Der Fehler bedeutet, Oracle kann nicht zwei Spalten mit mehr als 4000 Bytes jeweils in einer Update behandeln. In der Vergangenheit hatte Oracle bereits Probleme damit - ich erinnere mich an Versionen, wo nur eine LONG-Spalte pro Tabelle erlaubt war. Ich wundere mich, dass sie dieses Problem nicht beseitigt haben. (Ich weiß nicht, ob Sie wirklich eine zweite LONG oder LOB Spalte in dieser Tabelle haben, aber ich denke es wird eine geben.)

Ich denke, das Entfernen der @Type Annotation löst das Problem im Allgemeinen nicht. In Ihrem Test könnte der Effekt dann weniger als 4000 Bytes betragen, aber bei anderen Daten könnte der Fehler auch auftreten.

Lösung: Ich glaube, Sie die Update-Anweisung in zwei Anweisungen getrennt haben, wie das, was ich hier skizzieren (Batch-Update noch möglich ist):

for (many rows) { 
    object.setFirstLongColumn(...); 
    persist(object); 
    session.flush(); 
    object.setSecondLongColumn(...); 
    persist(object); 
    session.flush(); 
} 
commit(); 

Die session.flush() notwendig ist, Hibernate zu verhindern, um die Reihenfolge zu ändern der Datenbank-Anweisungen, die mit ou Logik interferieren könnten.

Eine weitere Sache: LONG is deprecated in Oracle. Wenn Sie Glück haben, dann löst das Ersetzen von LONG durch LOB in der Datenbank Ihr Problem.

+0

Das ist in der Tat das Problem. Wenn ich die Annotation "@ Type" entferne, wird Hibernate einem LOB zugeordnet und die Probleme mit Oracle sind verschwunden. Aber derselbe Code funktioniert nicht mit PostgreSQL (siehe die verknüpfte Frage) – Matteo

+0

Wenn Sie XML-Mapping-Dateien anstelle von Annotationen verwenden, könnten Sie verschiedene Zuordnungen für Oracle und PostgreSQL haben, die Ihr Problem lösen würden. Es gibt noch einige Vorteile von XML-Dateien. Wäre das eine Alternative für dich - zumindest für diesen Tisch? – Johanna

+0

Ich habe immer mit Annotationen gearbeitet, aber wenn das mein Problem lösen könnte, werde ich nachsehen ... – Matteo

1
@Lob 
private String someString; 

sagt Hibernate, dies als "materialisierten CLOB" zu behandeln. Ein CLOB aufgrund der Annotation @Lob, materialisiert, weil wir die Zeichenfolge/Zeichen aus dem CLOB-Locator extrahieren müssen.

Als ich CLOB- hier sage, meine ich java.sql.Types.CLOB. Also der JDBC-Typcode. Allerdings hat Hibernate hier eine andere Ebene der Indirektion: der Dialekt.Die Dialekte können definieren, wie Typcodes physischen Datenbanktypen (die beim Schema-Export, Cast-Aufrufe usw. verwendet werden) zugeordnet werden und wie Binde-/Extraktionsoperationen für PreparedStatement/ResultSet ausgeführt werden. Die PostgreSQL-Dialekte ordnet Types.CLOB dem physischen "Text" -Datentyp zu; die Oracle-Dialekte ordnen sie dem physischen CLOB-Datentyp zu; Die MySQL-Dialekte ordnen sie dem physischen "longtext" -Datentyp zu.

+0

genau. Jetzt ist mein Problem, dass ich mit der Standardzuordnung keine Probleme mit Oracle habe, aber ich habe Probleme mit UTF-8 Zeichen auf PostgreSQL. Wenn ich den Typ als "org.hibernate.type.TextType" spezifiziere, ist das Problem mit UTF-8 verschwunden, aber ich kann Objekte auf Oracle nicht einfach aktualisieren. – Matteo

+0

Gut sehen Sie meinen Kommentar zu der SO-Frage, die Sie verknüpft haben. Hauptsächlich, imo, das ist ein Problem mit verstaatlichten Zeichensatz-Unterstützung. –

+0

Das Problem, soweit ich das beurteilen kann, ist nicht mit verstaatlichten Zeichen, aber soweit ich mich erinnere mit dem Löschen von Bytes, wenn das Zeichen mehr als zwei Bytes belegt. Ich werde auf meine Dokumentation zurückblicken müssen, aber ich erinnere mich, dass wir das Mapping hinzufügen mussten, um dieses spezielle Problem mit dem PostgreSQL-Treiber oder Hibernate oder einer Kombination von beiden zu vermeiden. – Matteo

3

Das funktionierte für mich. Erweiterte PostgreSQL81Dialect wie folgt aus:

public class MyPostgreSQL81Dialect extends PostgreSQL81Dialect 
{ 

    @Override 
    public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) 
    { 
    SqlTypeDescriptor descriptor; 
    switch (sqlCode) 
    { 
     case Types.CLOB: 
     { 
     descriptor = LongVarcharTypeDescriptor.INSTANCE; 
     break; 
     } 
     default: 
     { 
     descriptor = super.getSqlTypeDescriptorOverride(sqlCode); 
     break; 
     } 
    } 
    return descriptor; 
    } 

} 
2

Kredite sollten an anderer Stelle gehen (an Benutzer genannt: @liecno), sondern auf der Grundlage eines von (seiner) Kommentare zu den Antworten in: Postgres UTF-8 clobs with JDBC die Kompatibilität mit Oracle sowie Postgres können einfach dadurch erreicht, über sein:

@Lob 
@Type(type="org.hibernate.type.StringClobType") 
private String someString; 

UPDATE:

OK, nach einigen Tests, kam ich zu noch mehr auf dem neuesten Stand Lösung, die für alle meine Szenarien gearbeitet. Als org.hibernate.type.StringClobType ist veraltet (Hibernate 4.2.x), ging ich zu seinem Ersatz: org.hibernate.type.MaterializedClobType.

@Lob 
@Type(type="org.hibernate.type.MaterializedClobType") 
private String someString;