2009-10-29 14 views
9

ADVERTENCIA: vea mi propia respuesta a continuación. El problema está causado por los controladores de Oracle antiguos que estaban presentes en el classpath además de 10.2.0.4. Problema resuelto. Dejando el resto de esta pregunta para la posteridad.Hibernar en Oracle: asignación de propiedad de cadena a la columna CLOB

He estado golpeando mi cabeza contra lo siguiente. He aquí una sencilla POJO destilado de mi código de aplicación:

@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; } 
} 

Hay una propiedad de cadena y una columna CLOB. Cuando el contenido es corto (por ejemplo, "hola mundo"), persiste muy bien. Con cadenas más largas, me sale el siguiente excepción:

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) 

estoy usando Hibernate 3.2.3 con Oracle JDBC controlador 10.2.0.4. El mensaje de la excepción indica que el procesamiento por lotes puede ser defectuoso. Aunque puedo deshabilitar el procesamiento por lotes en este caso simple, necesito tenerlo habilitado para los POJO "reales". De hecho, tal como están las cosas ahora, el procesamiento por lotes de consultas es la única razón por la que estamos usando Hibernate.

Entonces, mi pregunta es, ¿cómo puedo hacer que el trabajo anterior?

EDIT: Interesante observación: el valor de mi propiedad de "descripción" persiste muy bien, siempre y cuando sea exactamente de 1333 caracteres de longitud o menos. ¡Un número tan extraño!

EDIT 2: En un intento de encontrar una solución, que modifica los getProperty() anotaciones de la siguiente manera, que se ha hecho ninguna diferencia:

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

EDITAR 3: Aquí está el DDL para "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)) ; 

Y aquí está toda la pila:

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 

Respuesta

23

Alerta de Moron: resulta que tenía un JAR obsoleto con clases Oracle JDBC de 9 y tantos en mi classpath. Después de haber limpiado todo, todo simplemente funcionó mágicamente con solo las siguientes anotaciones:

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

Blame the fat fingers.

4

¿Has probado a soltar la anotación @Lob y anotarla con @Column? En mi experiencia, no es necesario que diga hibernar el tipo de columna para un CLOB, sino que lo determinará por sí mismo.

¿Puede incluir un fragmento del código de cliente que está realizando la operación de procesamiento por lotes?

+0

Estoy dando una prueba a su sugerencia, lo descubriremos en unos minutos. En cuanto a los lotes, no hay nada en mi propio código que haga lotes. Es una característica incorporada de Hibernate. Hay una anotación @BatchSize que usamos en asociaciones en la aplicación. Si miras el rastro de la pila en mi pregunta, puedes ver todas las llamadas por lotes que atraviesa Hibernate. –

+0

No, eliminar @Lob y simplemente dejar @Column y @Type no ayudó. He anotado la clase en sí con @BatchSize (tamaño = 0) para fines de aislamiento, aunque no es un curso de acción aceptable en general. –

+0

El truco @BatchSize (size = 0) tampoco ayudó. –

Cuestiones relacionadas