Estoy buscando una manera de transmitir datos binarios a/desde la base de datos. Si es posible, me gustaría que fuera hecho con Hibernate (en una base de datos de manera independiente). Todas las soluciones que he encontrado implican la carga explícita o implícita de datos binarios en la memoria como byte []. Necesito evitarlo. Digamos que quiero que mi código pueda escribir en un archivo local un video de 2GB de la base de datos (almacenado en la columna BLOB), o al revés, usando no más de 256Mb de memoria. Es claramente alcanzable, y no implica vudú. Pero no puedo encontrar la manera, por ahora estoy tratando de evitar la depuración de Hibernate.Cómo transmitir datos a la base de datos BLOB usando Hibernate (sin almacenamiento en memoria en byte [])
Miremos el código de muestra (teniendo en cuenta -Jmx = 256Mb).
clase Entidad:
public class SimpleBean {
private Long id;
private Blob data;
// ... skipping getters, setters and constructors.
}
Hibernate fragmento de mapeo:
<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>
prueba fragmento de código:
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();
Cuando se ejecuta fragmento que llego excepción OutOfMemory. Observar el seguimiento de la pila muestra qué Hibernate intenta cargar la secuencia en la memoria y obtiene OutOfMemory (como debería). Aquí está el seguimiento de la pila:
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)
Usado Hibernate 4.1.5.SP1. La pregunta exacta es: cómo evitar cargar flujo en la memoria cuando se almacena un blob en la base de datos usando Hibernate, usando transmisión directa en su lugar. Me gustaría evitar los temas sobre por qué uno almacena el video en la columna de la base de datos en lugar de almacenarlo en algún repositorio de contenido y vincularlo. Por favor, considere un modelo lo que es irrelevante para la pregunta.
Parece que podría haber algún tipo de capacidades en diferentes dialectos e Hibernate podría intentar cargar todo en la memoria, porque la base de datos subyacente no es compatible con streaming blobs o algo así. Si es el caso, me gustaría ver algún tipo de tabla comparativa entre diferentes dialectos en el aspecto del manejo de blobs.
¡Muchas gracias por su ayuda!
Save yourse Si alguna vez, no intente evitar la depuración.) – IceGlow