I’m having an issue with streaming large files to the oracle DB using Spring Boot and Hibernate.
This issue occurs after a Spring Boot Upgrade to 3.4.1 (from 3.2.5), which includes the new minor version Hibernate 6.6.4. I’m using oracle driver ojdbc8-21.3.0.0.
I have an entity definition like this
import java.sql.Blob;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Lob;
@Entity
public class Table
{
@Lob
@Column(name = "data")
private Blob data;
}
In order to stream a large input file to the database I’m using BlobProxy.generateProxy(in, length)
to set up the blob proxy with my input stream.
Upon transaction commit I now get the following exception:
Caused by: java.lang.ClassCastException: class org.hibernate.engine.jdbc.BlobProxy cannot be cast to class oracle.jdbc.internal.OracleBlob (org.hibernate.engine.jdbc.BlobProxy and oracle.jdbc.internal.OracleBlob are in unnamed module of loader 'app')
at oracle.jdbc.driver.OraclePreparedStatement.setBlob(OraclePreparedStatement.java:6528)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setBlob(OraclePreparedStatementWrapper.java:153)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setBlob(HikariProxyPreparedStatement.java)
at org.hibernate.type.descriptor.jdbc.BlobJdbcType$4$1.doBind(BlobJdbcType.java:173)
at org.hibernate.type.descriptor.jdbc.BlobJdbcType$2$1.doBind(BlobJdbcType.java:115)
at org.hibernate.type.descriptor.jdbc.BasicBinder.bind(BasicBinder.java:61)
at org.hibernate.engine.jdbc.mutation.internal.JdbcValueBindingsImpl.lambda$beforeStatement$0(JdbcValueBindingsImpl.java:87)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.hibernate.engine.jdbc.mutation.spi.BindingGroup.forEachBinding(BindingGroup.java:51)
at org.hibernate.engine.jdbc.mutation.internal.JdbcValueBindingsImpl.beforeStatement(JdbcValueBindingsImpl.java:85)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:130)
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorSingleNonBatched.performNonBatchedOperations(MutationExecutorSingleNonBatched.java:55)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:55)
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.doStaticInserts(InsertCoordinatorStandard.java:194)
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.coordinateInsert(InsertCoordinatorStandard.java:132)
at org.hibernate.persister.entity.mutation.InsertCoordinatorStandard.insert(InsertCoordinatorStandard.java:104)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:110)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:644)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:511)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:414)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:41)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1429)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:2354)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:1978)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:439)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:169)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:267)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
This seems to be related to HHH-18206, and HHH-18206 Switch to JDBC LOB APIs for Oracle Dialect by loiclefevre · Pull Request #8486 · hibernate/hibernate-orm · GitHub, where the binding of the blog type changed from STREAM_BINDING to BLOB_BINDING in the org.hibernate.type.descriptor.jdbc.BlobJdbcType. While hibernate unwraps the blob to the java.sql.Blob type, the oracle driver seems to expect an instance of oracle.jdbc.internal.OracleBlob.
Is there an alternative ways to create a blob proxy now from an input stream? Or maybe an alternative way to stream large objects to the DB that works for oracle?
I’m happy to provide more details if necessary.