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
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. –
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. –
El truco @BatchSize (size = 0) tampoco ayudó. –