37

I have a JPA entity with java.sql.Blob:

@Entity
public class LargeData {

  @Lob
  private java.sql.Blob data;

  //getters/setters
}

How to create instance of this entity? I want to set Blob with setData() method, but how to get Blob from JPA? java.sql.Blob is only interface, there are different implementations for different databases, so I assume JPA should give me right implementation. How to get it?

2 Answers 2

61

Use a byte array:

@Lob
@Column(length=100000)
private byte[] data;

If you want to use streams, create the blob using Hibernate.createBlob(..)

Sign up to request clarification or add additional context in comments.

3 Comments

Additional info to the accepted answer. Confirmed by personal experience in 2016. stackoverflow.com/a/16599953/102658 tl;dr: > length attribute is used to define the > column length of String fields (it is ignored for other types)
This uses a clob for me, not a blob.
I don't specify the length attribute. I also use java nio to read from a file : myEntity.data = Files.readAllBytes(myPath).
6

use a file stream. However, this appears to have various complications, depending on your database, driver, and JPA implementation. I built a generic solution, that was slow, and failed with large files, then found a Hibernate-specific solution that worked with Oracle 11.2.0.4

I'm using Spring Data / JPA, but the issue seems to be around Hibernate, not Spring.

Hibernate:

private void testLoadFile() throws SQLException, IOException {


  File f = new File("//C:/tmp/6mb_file.wmv");
  BufferedInputStream fstream = new BufferedInputStream(new FileInputStream(f));

  Session session = entityManager.unwrap(Session.class);
  Blob blob = Hibernate.getLobCreator(session).createBlob(fstream, f.length());

  FileBLOBEntity file = new FileBLOBEntity();

  file.setName("//C:/tmp/6mb_file.wmv");
  file.setTheData(blob);
  blobRepository.saveAndFlush(file);
}

Generic Spring/JPA:

private void testLoadFile() throws SQLException, IOException {

  File f = new File("//C:/tmp/6mb_file.wmv");
  BufferedInputStream fstream = new BufferedInputStream(new FileInputStream(f));

  Blob blob = connection.getConnection().createBlob();
  BufferedOutputStream bstream = new  BufferedOutputStream(blob.setBinaryStream(1));
  // stream copy runs a high-speed upload across the network
  StreamUtils.copy(fstream, bstream);

  FileBLOBEntity file = new FileBLOBEntity();

  file.setName("//C:/tmp/6mb_file.wmv");
  file.setTheData(blob);
  // save runs a low-speed download across the network.  this is where
  // Spring does the SQL insert.  For a large file, I get an OutOfMemory exception here.
  blobRepository.saveAndFlush(file);
}

and for retrieval:

public void unloadFile() throws SQLException, IOException {

  File f = new File("//C:/tmp/6mb_file.wmv" + "_fromDb");

  FileOutputStream fstream = new FileOutputStream(f);

  FileBLOBEntity file = blobRepository.findByName("//C:/tmp/6mb_file.wmv");
  Blob data = file.getTheData();

  InputStream bstream = data.getBinaryStream();
  StreamUtils.copy(bstream, fstream);

}

3 Comments

works but is Hibernate specific, if you use EclipseLink it would break
... which I stated at the top of the post. I don't like to be implementation-specific, but this was the only solution I found that was both stable and fast enough.
I'm using Spring Boot 3.4 (Hibernate 6). This helped me a lot, thanks!. In my case, the saveAndFlush made the difference, because with save, the stored Blob was empty

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.