14 Stimmen

Hibernate auf Oracle: Zuordnung der String-Eigenschaft zur CLOB-Spalte

WARNUNG : siehe meine eigene Antwort unten. Das Problem wird durch alte Oracle-Treiber verursacht, die zusätzlich zu 10.2.0.4 auf dem Klassenpfad vorhanden waren. Problem gelöst. Ich lasse den Rest dieser Frage für die Nachwelt stehen.

Ich habe mir den Kopf über Folgendes zerbrochen. Hier ist ein einfaches POJO aus meinem Anwendungscode destilliert:

@Entity
@Table(name = "PIGGIES")
public class Piggy {    
    private Long id;
    private String description;

    public Piggy() {}

    @Id
    @GeneratedValue
    @Column(name = "PIGGY_ID")
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

    @Lob
    @Column(name = "PIGGY_DESCRIPTION")
    public String getDescription() { return description; }
    public void setDescription(String d) { description = d; }
}

Es gibt eine String-Eigenschaft und eine CLOB-Spalte. Wenn der Inhalt kurz ist (z. B. "hello world"), bleibt er problemlos erhalten. Mit längeren Zeichenfolgen, erhalte ich die folgende Ausnahme:

java.sql.SQLException: operation not allowed: streams type cannot be used in batching
        at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
        at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
        at oracle.jdbc.driver.OraclePreparedStatement.addBatch(OraclePreparedStatement.java:4236)
        at org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:172)
        at org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:172)
        at org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:31)
        at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2403)

Ich verwende Hibernate 3.2.3 mit dem Oracle JDBC-Treiber 10.2.0.4. Die Ausnahmemeldung weist darauf hin, dass die Stapelverarbeitung fehlerhaft sein könnte. Während ich das Batching in diesem einfachen Fall deaktivieren kann, muss ich es für die "echten" POJOs aktivieren. So wie die Dinge im Moment stehen, ist das Query Batching der einzige Grund, warum wir Hibernate überhaupt verwenden.

Meine Frage lautet also: Wie kann ich die oben genannten Maßnahmen umsetzen?

EDIT : Interessante Beobachtung: Der Wert meiner Eigenschaft "description" bleibt erhalten, solange er genau 1333 Zeichen lang oder kürzer ist. Solch eine ungerade Zahl!

EDIT 2 : In einem Versuch, eine Lösung zu finden, habe ich die getProperty() Anmerkungen wie folgt, was keinen Unterschied gemacht hat:

@Lob
@Type(type="text")
@Column(name = "PIGGY_DESCRIPTION", length = Integer.MAX_VALUE)
public String getDescription() { return description; }

EDIT 3 : Hier ist die DDL für "PIGGIES":

CREATE TABLE "PIGGIES" 
 (  "PIGGY_ID" NUMBER NOT NULL ENABLE, 
"PIGGY_DESCRIPTION" CLOB, 
 CONSTRAINT "PIGGIES_PK" PRIMARY KEY ("PIGGY_ID")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 
STORAGE(INITIAL 1048576 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "BBDATA"  ENABLE
 ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 1048576 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
  TABLESPACE "BBDATA" 
LOB ("PIGGY_DESCRIPTION") STORE AS "SYS_LOB0000177753C00002$$"(
TABLESPACE "BBDATA" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
NOCACHE 
STORAGE(INITIAL 1048576 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)) ;

Und hier ist der gesamte Stapel:

org.hibernate.exception.GenericJDBCException: could not update: [com.bamnetworks.cms.types.Piggy#934]
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2425)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2307)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2607)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:92)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
Caused by: java.sql.SQLException: operation not allowed: streams type cannot be used in batching
    at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
    at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
    at oracle.jdbc.driver.OraclePreparedStatement.addBatch(OraclePreparedStatement.java:4236)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:172)
    at org.apache.commons.dbcp.DelegatingPreparedStatement.addBatch(DelegatingPreparedStatement.java:172)
    at org.hibernate.jdbc.BatchingBatcher.addToBatch(BatchingBatcher.java:31)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2403)
    ... 45 more

32voto

Max A. Punkte 4730

Idiotenalarm: Es stellte sich heraus, dass ich ein veraltetes JAR mit 9 oder mehr Oracle JDBC-Klassen in meinem Klassenpfad hatte. Nachdem ich das bereinigt hatte, funktionierte alles wie von Zauberhand mit nur den folgenden Anmerkungen:

@Lob
@Column(name = "PIGGY_DESCRIPTION")
public String getDescription() { return description; }

Schuld sind die dicken Finger.

5voto

Jherico Punkte 27127

Haben Sie versucht, die @Lob Anmerkung und nur die Anmerkung mit @Column ? Meiner Erfahrung nach brauchen Sie Hibernate den Spaltentyp für eine CLOB nicht mitzuteilen, er wird ihn selbst bestimmen.

Können Sie einen Ausschnitt des Client-Codes einfügen, der den Stapelverarbeitungsvorgang durchführt?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X