Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring-data-jpa storing blob

What is "best" or canonical way to store entity with blob using spring-data-jpa?

@Entity
public class Entity {
  @Id
  private Long id;
  @Lob()
  private Blob blob;
}

public interface Repository extends CrudRepository<Entity,  Long> {
}
like image 580
user482745 Avatar asked Jul 17 '15 05:07

user482745


2 Answers

You can do it with a single statement (4 below) using Hibernate.getLobCreator and passing the session that EntityManager can unwrap to you:

// 1. Get entity manager and repository
EntityManager em = .... // get/inject someway the EntityManager
EntityRepository repository = ...// get/inject your Entity repository

// 2. Instantiate your Entity
Entity entity = new Entity();

// 3. Get an input stream (you shall also know its length)
File inFile = new File("/somepath/somefile");
InputStream inStream = new FileInputStream(inFile);

// 4. Now copy to the BLOB
Blob blob =
  Hibernate.getLobCreator(em.unwrap(Session.class))
           .createBlob(inStream, inFile.length());

// 5. And finally save the BLOB
entity.setBlob(blob);
entityRepository.save(f);
like image 118
Franco G Avatar answered Sep 19 '22 12:09

Franco G


TL; DR

You can see sample project on my github. The project shows how you stream data to/from database.

Problem

All advices about mapping the @Lob as byte[] defeats (IMO) the main advantage of blobs - streaming. With byte[] everything gets loaded in memory. May be ok but if you go with LargeObject you likely want to stream.

Solution

Mapping

@Entity
public class MyEntity {

    @Lob
    private Blob data;

    ...

}

Configuration

Expose hibernate SessionFactory and CurrentSession so you can get hold of the LobCreator. In application.properties:

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext

Expose session factory as bean:

@Bean // Need to expose SessionFactory to be able to work with BLOBs
public SessionFactory sessionFactory(HibernateEntityManagerFactory hemf) {
    return hemf.getSessionFactory();
}

Create blob

@Service
public class LobHelper {

    private final SessionFactory sessionFactory;

    @Autowired
    public LobHelper(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public Blob createBlob(InputStream content, long size) {
        return sessionFactory.getCurrentSession().getLobHelper().createBlob(content, size);
    }

    public Clob createClob(InputStream content, long size, Charset charset) {
        return sessionFactory.getCurrentSession().getLobHelper().createClob(new InputStreamReader(content, charset), size);
    }
}

Also - as pointed out in comments - as long as you work with the @Blob including the stream you get you need to be within transaction. Just mark the working part @Transactional.

like image 38
Jan Zyka Avatar answered Sep 18 '22 12:09

Jan Zyka