I have a project with Spring and Hibernate. In my implementation, there are multiple models where I have to read from a file and store it as a Blob. For this purpose, I have an abstract class defined with Blob as follows. All the model that need to store blobs extend this class.
@MappedSuperclass
public abstract class AbstractContentAwareBean {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
protected Long id;
public AbstractContentAwareBean() {}
@Lob
@Column(name = "content", columnDefinition = "LONGBLOB")
protected Blob content;
public void setContent(Blob content) {
this.content = content;
}
public void setContent(Session currentSession, InputStream inputStream, long size) {
Blob blob = Hibernate.getLobCreator(currentSession).createBlob(inputStream, size);
setContent(blob);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@JsonIgnore
public Blob getContent() {
return content;
}
}
Here is a sample usage of this.
@Transactional
public void sampleMethod() throws Exception {
try {
// I have entity manager auto-wired.
Session session = entityManager.unwrap(Session.class);
File file = new File("/tmp/filepath.txt");
MySampleModel sm = new MySampleModel();
sm.setContent(session, new FileInputStream(file), file.length());
// I have service auto wired. persistSampleModel simply calls mySampleRepository.save(sm)
mySampleModelService.persistSampleModel(sm);
} catch (Exception e) {
// log and throw
throw new Exception("Error occurred", e);
}
}
Now the problem I face is that the FileInputStream I open here is not released. I checked with lsof -p <process_id>
command and those file descriptors remain.
I checked the implementation path of Blob creation and the stream goes through org.hibernate.engine.jdbc.BlobProxy
and ends up in org.hibernate.engine.jdbc.BlobProxy.StreamBackedBinaryStream
which has a release
method but it is not called automatically. Therefore I believe we have to call the Blob.free()
method manually to get the release called.
Attempt 1: try-with-resources
I get the following trace when I wrap the stream with try-with-resources
. I believe the issue here is that the stream is read only when the transaction commits and by then try-with-resources
has closed the stream.
Caused by: java.io.IOException: Stream Closed
at java.io.FileInputStream.readBytes(Native Method) ~[?:1.8.0_151]
at java.io.FileInputStream.read(FileInputStream.java:255) ~[?:1.8.0_151]
at com.mysql.cj.jdbc.PreparedStatement.readblock(PreparedStatement.java:2612) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.streamToBytes(PreparedStatement.java:4302) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2144) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2013) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:1970) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:4984) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at com.mysql.cj.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1955) ~[mysql-connector-java-6.0.5.jar:6.0.5]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:205) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.dialect.identity.GetGeneratedKeysDelegate.executeAndExtract(GetGeneratedKeysDelegate.java:57) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:42) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2909) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3480) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:626) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:280) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:261) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:306) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:318) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:275) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:804) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:771) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:80) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:414) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:252) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:113) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:780) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:765) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at com.sun.proxy.$Proxy76.persist(Unknown Source) ~[?:?]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) ~[spring-data-jpa-1.11.6.RELEASE.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.6.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.6.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.6.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.6.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 48 more
Attempt 2: javax.persistence.PostPersist
annotated method to call Blob.free()
method
@PostPersist
public void postPersist(){
try {
this.content.free();
} catch (SQLException ignore) {}
}
This was successful in most of the cases than the try with resources attempt. Yet in CascadeType.MERGE
cases where one model uses another, this attempt also fails.
Caused by: org.hibernate.exception.GenericJDBCException: unable to merge BLOB data
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.dialect.Dialect$3.mergeBlob(Dialect.java:597) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.BlobType.getReplacement(BlobType.java:39) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.BlobType.getReplacement(BlobType.java:20) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.AbstractStandardBasicType.replace(AbstractStandardBasicType.java:353) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.TypeHelper.replace(TypeHelper.java:180) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:394) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:203) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:873) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:461) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:202) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:881) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:867) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at com.sun.proxy.$Proxy160.merge(Unknown Source) ~[?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at com.sun.proxy.$Proxy160.merge(Unknown Source) ~[?:?]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:511) ~[spring-data-jpa-1.11.5.RELEASE.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 137 more
Caused by: javax.sql.rowset.serial.SerialException: Error: You cannot call a method on a SerialBlob instance once free() has been called.
at javax.sql.rowset.serial.SerialBlob.isValid(SerialBlob.java:592) ~[?:1.8.0_151]
at javax.sql.rowset.serial.SerialBlob.getBinaryStream(SerialBlob.java:220) ~[?:1.8.0_151]
at org.hibernate.dialect.Dialect$3.mergeBlob(Dialect.java:594) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.BlobType.getReplacement(BlobType.java:39) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.BlobType.getReplacement(BlobType.java:20) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.AbstractStandardBasicType.replace(AbstractStandardBasicType.java:353) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.type.TypeHelper.replace(TypeHelper.java:180) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:394) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:203) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:903) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:873) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:458) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:383) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:461) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:202) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:881) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:867) ~[hibernate-core-5.2.10.Final.jar:5.2.10.Final]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at com.sun.proxy.$Proxy160.merge(Unknown Source) ~[?:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at com.sun.proxy.$Proxy160.merge(Unknown Source) ~[?:?]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:511) ~[spring-data-jpa-1.11.5.RELEASE.jar:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.5.RELEASE.jar:?]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 137 more
Questions:
Does hibernate or spring generally release the Blobs automatically? If so could it be a configuration problem?
If hibernate or spring does not release blob automatically, how can we release the Blob in such scenarios?
Let me share my confugurations as well. Hope some of you could help me. Thanks in advance.
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:packagesToScan="org.sample.model" p:dataSource-ref="dataSource">
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${spring.jpa.hibernate.ddl-auto}</prop>
<prop key="hibernate.implicit_naming_strategy">${spring.jpa.hibernate.naming.implicit-strategy}</prop>
<prop key="hibernate.physical_naming_strategy">${spring.jpa.hibernate.naming.physical-strategy}</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="${spring.jpa.show-sql}"/>
<property name="databasePlatform" value="${spring.jpa.database-platform}"/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<jpa:repositories base-package="org.sample.repository"/>
<context:component-scan base-package="org.sample.repository"/>
P.S: The usage of FileInputStream
in the above sample method is to simplify the issue. Actually, in the code, I used an UltraESB-X API to read a stream from a temporary file created by the ESB.
Since there were no answers for this, I'll post mine. The solution we could come up with was to write a class which wraps an input stream and closes it automatically once the reading is complete.
This class was used in the
AbstractContentAwareBean
class as follows.Would like to thank the folks including the people who answered my question at code review for helping me write the
SelfClosingInputStream
class.