当前位置: 首页 > 面试题库 >

如何使用Hibernate将数据流传输到数据库BLOB(无内存存储在byte []中)

裘光启
2023-03-14
问题内容

我正在寻找一种将二进制数据流传输到数据库或从数据库流传输二进制数据的方法。如果可能的话,我希望使用Hibernate来完成(以与数据库无关的方式)。我发现的所有解决方案都涉及将字节数据作为byte
[]显式或隐式加载到内存中。我要避免它。假设我希望我的代码能够使用不超过256Mb的内存将数据库中的2GB视频(存储在BLOB列中)写入本地文件,或者以其他方式将其写入本地文件。这显然是可以实现的,并且不涉及任何巫毒。但是我找不到办法,因为现在我正尝试避免调试Hibernate。

让我们看一下示例代码(请记住-Jmx = 256Mb)。

实体类:

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代替直接流传输将blob存储在数据库中时,如何避免将流加载到内存中。我想避免有关为何将视频存储在数据库列而不是将其存储在某些内容存储库和链接中的主题。请考虑它与问题无关的模型。

似乎不同的方言可能具有某种功能,并且Hibernate可能会尝试将所有内容加载到内存中,因为基础数据库不支持流blob或类似的功能。如果是这样,我想在处理Blob方面看到不同方言之间的某种比较表。

非常感谢您的帮助!


问题答案:

对于那些寻找相同事物的人。

不好的是,该代码对于PostgreSQL(可能还有很多其他)而言按预期工作(流而不尝试复制到内存)。Hibernate的内部工作取决于所选的方言。我首先使用的是优先使用流,而直接使用由byte
[]支持的BinaryStream。

此外,性能也没有问题,因为在PostgreSQL情况下,它仅加载OID(数字),而在其他方言(包括byte
[]实现)的情况下,可能懒加载数据。只是进行了一些肮脏的测试,在有和没有二进制数据字段的情况下,在10000个实体加载中没有明显的差异。

不过,将数据存储在数据库中似乎比仅将其作为外部文件保存在磁盘上要慢。但是,这在备份或处理特定文件系统的限制或并发更新等时为您省去了很多麻烦。但这是不合时宜的。



 类似资料:
  • 问题内容: 我已经搜索了很多有关此问题的信息,但是我没有针对我的问题找到合适的解决方案,我有以下使用Java存储文件的方法, 当我尝试运行此代码时,出现以下错误, 请帮助我。 问题答案: 将文件数据转换为字节数组并在sql语句中设置

  • 我试图将一个Azure Blob存储容器挂载到一个DataBricks实例上,虽然挂载确实有效,但它似乎没有使用存储容器。 我在这里漏掉了什么?

  • 问题内容: 您好,我在较早之前发布了此内容,并获得了一些帮助,但仍然没有有效的解决方案。由于最后的问与答,我确定我的“保存到数据库”代码以及“检索到图片”代码有问题。即使我手动将图片保存在数据库中,它也不会恢复。这是我从网络上的3或4个示例中修补而成的代码。理想情况下,如果有人拥有一些已知的良好代码,并且可以指导我这样做,那将是最好的。 ![在此处输入图片描述] [1] ‘*使用以下代码检索到图片

  • 我刚开始冬眠。我需要在postgres中存储文件,列的数据类型是。我在互联网上四处寻找这个案例的工作演示,但我找不到任何。 Hibernate映射:

  • 问题内容: 有人可以告诉我,在以下情况下如何进行? 接收文件(MS文件,ODS,PDF) 通过Apache Tika提取公元核心元数据+通过jackrabbit-content-extractors提取内容 使用Jackrabbit将文档(内容)及其元数据存储到存储库中 ? 检索文档+元数据 我对第3点和第4点感兴趣… 详细信息:该应用程序正在以交互方式处理文档(一些分析-语言检测,单词计数等。+

  • 我创建了一个TextView,它以多行显示值 ,我希望将该值保留在SQLite数据库中。这是我使用的代码: 问题是当我保存值时,整个值被插入到一个单元格中。我希望每行的值分开,然后插入到每行的单个单元格中,尽管我使用扫描器方法插入数据,但它不起作用。那有什么办法吗?