java - 如何使用 hibernate 和 spring @transactional 释放 blob?
问题描述
我有一个 Spring 和 Hibernate 项目。在我的实现中,有多个模型我必须从文件中读取并将其存储为 Blob。为此,我有一个用 Blob 定义的抽象类,如下所示。所有需要存储 blob 的模型都扩展了这个类。
@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;
}
}
这是一个示例用法。
@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);
}
}
现在我面临的问题是我这里打开的FileInputStream没有释放。我用lsof -p <process_id>
命令检查了这些文件描述符。
我检查了 Blob 创建的实现路径,流通过org.hibernate.engine.jdbc.BlobProxy
并最终在org.hibernate.engine.jdbc.BlobProxy.StreamBackedBinaryStream
其中有一个release
方法,但它不会自动调用。因此,我相信我们必须Blob.free()
手动调用该方法才能调用该版本。
尝试1:try-with-resources
当我用try-with-resources
. 我相信这里的问题是只有在事务提交时才读取流,然后try-with-resources
关闭流。
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
尝试2:javax.persistence.PostPersist
注解方法调用Blob.free()
方法
@PostPersist
public void postPersist(){
try {
this.content.free();
} catch (SQLException ignore) {}
}
在大多数情况下,这比尝试使用资源尝试成功。然而,CascadeType.MERGE
在一个模型使用另一个模型的情况下,这种尝试也会失败。
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
问题:
hibernate 或 spring 通常会自动释放 Blob 吗?如果是这样可能是配置问题吗?
如果hibernate或者spring没有自动释放blob,这种场景下怎么释放blob呢?
让我也分享一下我的配置。希望你们中的一些人可以帮助我。提前致谢。
<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"/>
PS:FileInputStream
上述示例方法中的使用是为了简化问题。实际上,在代码中,我使用UltraESB-X API从 ESB 创建的临时文件中读取流。
解决方案
由于没有答案,我会发布我的。我们可以想出的解决方案是编写一个类来包装输入流并在读取完成后自动关闭它。
/**
* Purpose of this class is to wrap an input stream and close it automatically once the reading is complete.
*
* @author Rajind Ruparathna
*/
public class SelfClosingInputStream extends FilterInputStream {
private static final int EOF = -1;
private boolean isClosed = false;
private Long length;
private Long count = 0L;
public SelfClosingInputStream(InputStream is, Long length) {
super(is);
this.length = length;
}
public SelfClosingInputStream(InputStream is) {
super(is);
length = -1L;
}
@Override
public int read() throws IOException {
try {
if (!isClosed) {
int val = super.read();
count = count + 1;
if ((length != -1L && count.equals(length)) || val == EOF) {
close();
isClosed = true;
}
return val;
} else {
return EOF;
}
} catch (IOException e) {
close();
isClosed = true;
throw e;
}
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
try {
if (!isClosed) {
int val = super.read(b, off, len);
count = count + val;
if ((length != -1L && count.equals(length)) || val == EOF) {
close();
isClosed = true;
}
return val;
} else {
return EOF;
}
} catch (IOException e) {
close();
isClosed = true;
throw e;
}
}
}
该类在类中使用AbstractContentAwareBean
如下。
public void setContent(Session currentSession, InputStream inputStream, long size) {
Blob blob = Hibernate.getLobCreator(currentSession).createBlob(new SelfClosingInputStream(inputStream, size), size);
setContent(blob);
}
想感谢那些帮助我编写课程的人,包括在代码审查中回答我的问题SelfClosingInputStream
的人。
推荐阅读
- html - 提交后尝试将表单输入字段重置为空白
- excel - Excel VBA:基于列标签的数据透视表的条件格式
- c++ - C ++中的异常类不起作用
- java - ApachePOI使用Java生成带有图像的excel(Autosize Row)
- selenium - 如何通过类名和可访问性 ID 定位元素?
- swift - 多线程核心数据有时会返回 nil 属性
- c# - Entity Framework 查询奇怪的参数
- php - Wordpress 函数在 bash 中运行的 php 脚本中不起作用
- java - 如何在 Spring Boot 中检查日志记录实现细节
- android - 如何使图像适应手机屏幕