我正在寻找将二进制数据传输到数据库/从数据库传输数据的方法。如果可能的话,我想用Hibernate来完成(以数据库不可知的方式)。 我发现的所有解决方案都包括将二进制数据以byte []形式显式或隐式加载到内存中。我需要避免它。比方说,我希望我的代码能够从数据库(存储在BLOB列中)向本地文件写入2GB视频,或者反过来,使用不超过256Mb的内存。这显然是可以实现的,并且不涉及巫毒。但我找不到方法,现在我试图避免调试Hibernate。我们来看看示例代码(记住-Jmx = 256Mb)。如何使用Hibernate将数据流式传输到数据库BLOB(无内存中存储在字节[]中)
实体类:
public class SimpleBean {
private Long id;
private Blob data;
// ... skipping getters, setters and constructors.
}
Hibernate映射片段:
<class name="SimpleBean" table="SIMPLE_BEANS">
<id name="id" column="SIMPLE_BEAN_ID">
<generator class="increment" />
</id>
<property name="data" type="blob" column="DATA" />
</class>
测试的代码片段:
Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(cfg.getProperties())
.buildServiceRegistry();
SessionFactory sessionFactory = cfg.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
File dataFile = new File("movie_1gb.avi");
long dataSize = dataFile.length();
InputStream dataStream = new FileInputStream(dataFile);
LobHelper lobHelper = session.getLobHelper();
Blob dataBlob = lobHelper.createBlob(dataStream, dataSize);
session.save(new SimpleBean(data));
session.getTransaction().commit(); // Throws java.lang.OutOfMemoryError
session.close();
blobStream.close();
sessionFactory.close();
如果运行的片段,我得到了OutOfMemory例外。查看堆栈跟踪显示了Hibernate尝试将内容加载到内存中并获取OutOfMemory(应该如此)。这里的堆栈跟踪:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2271)
at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:113)
at java.io.ByteArrayOutputStream.ensureCapacity(ByteArrayOutputStream.java:93)
at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:140)
at org.hibernate.type.descriptor.java.DataHelper.extractBytes(DataHelper.java:183)
at org.hibernate.type.descriptor.java.BlobTypeDescriptor.unwrap(BlobTypeDescriptor.java:121)
at org.hibernate.type.descriptor.java.BlobTypeDescriptor.unwrap(BlobTypeDescriptor.java:45)
at org.hibernate.type.descriptor.sql.BlobTypeDescriptor$4$1.doBind(BlobTypeDescriptor.java:105)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:92)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:305)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:300)
at org.hibernate.type.AbstractSingleColumnStandardBasicType.nullSafeSet(AbstractSingleColumnStandardBasicType.java:57)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2603)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2857)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3301)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:275)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1214)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at ru.swemel.msgcenter.domain.SimpleBeanTest.testBasicUsage(SimpleBeanTest.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
用过的Hibernate 4.1.5.SP1。确切的问题是:如何避免在使用Hibernate将数据库存储在数据库中时将流加载到内存中,而不是直接使用流。我想避开关于为什么将视频存储在数据库列中而不是将其存储在某个内容存储库和链接中的主题。请认为它是一个与问题无关的模型。
似乎在不同的方言可能有某种功能,Hibernate可能会尝试将所有内容加载到内存中,因为底层数据库不支持流式blob或类似的东西。如果是这样的话 - 我想在处理斑点方面看到不同方言之间的某种比较表。
非常感谢您的帮助!
Save yourrse如果有一段时间,不要试图避免调试。 ) – IceGlow 2012-08-14 06:46:40