Как передавать данные в BLOB-объект базы данных с помощью Hibernate (no in -хранение в памяти в byte[])

Я ищу способ потоковой передачи двоичных данных в/из базы данных. Если возможно, я бы хотел, чтобы это было сделано с помощью Hibernate (независимо от базы данных ). Все решения, которые я нашел, включают явную или неявную загрузку двоичных данных в память как byte[]. Мне нужно избежать этого. Допустим, я хочу, чтобы мой код мог записать в локальный файл 2 ГБ видео из базы данных (, хранящейся в столбце BLOB ), или наоборот, используя не более 256 МБ памяти. Это вполне достижимо и не требует вуду. Но не могу найти способ, пока пытаюсь избежать отладки 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, используя вместо этого прямую потоковую передачу. Я хотел бы избежать нестандартных тем о том, почему видео хранится в столбце базы данных, а не хранится в каком-либо репозитории контента и связывается. Пожалуйста, считайте это моделью, которая не имеет отношения к вопросу.

Кажется, что на разных диалектах могут быть какие-то возможности, и Hibernate может попытаться загрузить все в память, потому что базовая база данных не поддерживает потоковую передачу больших двоичных объектов или что-то в этом роде.Если это так, -я хотел бы увидеть какую-то сравнительную таблицу между различными диалектами с точки зрения обращения с каплями.

Большое спасибо за Вашу помощь!

7
задан IceGlow 12 August 2012 в 22:51
поделиться