How to stream data to database BLOB using Hibernate (no in-memory storing in byte[])

半城伤御伤魂 提交于 2019-11-28 20:55:44

For those looking for same thing.

My bad, the code works as supposed to (streams without trying to copy to memory) for PostgreSQL (and probably lots of others). The inner work of Hibernate depends on selected dialect. The one I used in the first place overrides direct use of streams in favor of BinaryStream backed by byte[].

Also there are no problems with performance, since it loads only OID (number) in case of PostgreSQL, and probably lazy loads data in case of other dialects (including byte[] implementation). Just ran some dirty tests, no visible difference in 10000 loads of entity with and without binary data field.

Storing data in database seems to be slower than just saving it on disk as external file though. But it saves you a lot of headache when backing up, or dealing with limitations of particular file system, or concurrent updates, etc. But it's an off-topic.

Your solution using Hibernate's lobHelper should work, but you may need to make sure that the use of streams is enforced. Set property hibernate.jdbc.use_streams_for_binary = true This is a system-level property, so it has to be set at startup (I defined it on the command line during testing:

java -Dhibernate.jdbc.use_streams_for_binary=true blobTest

You can prove it's changed in your code:

Object prop = props.get("hibernate.jdbc.use_streams_for_binary");
System.out.println("hibernate.jdbc.use_streams_for_binary" + "/" + prop);

You are storing the Blob in your POJO SimpleBean. This means if the blob is larger than your heap space, anytime you work with this object or access the data field, you're going to get the OutOfMemoryError because the entire thing is loaded into memory.

I don't think there's a way to set or get a database field using a Stream in hibernate, and HQL inserts only into SELECT statements.

What you may have to do is remove the data field from the SimpleBean object so that it's not stored in memory when you load or save. But when you need to save a blob, you can use hibernate's save() to create the row, then use a jdbc PreparedStatement and the setBinaryStream() method. When you need to access the stream, you can use hibernate's load() method to get a SimpleBean object and do a jdbc select to get a ResultSet then use the getBinaryStream() method to read the blob. The docs for setBinaryStream() say:

The data will be read from the stream as needed until end-of-file is reached.

So the data won't be stored entirely in memory.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!