85

I am currently working on an application that uses Spring Boot and Spring Data (its JpaRepository interfaces to be precise) together with Hibernate.

One thing I love about Hiberante is its caching feature - when you submit multiple queries that match a particular object, you will get back the same instance of that object on every query execution (with respect to Java's == operator). However, when using Spring Data and JpaRepository classes, this does not always seem to be the case. For that reason, I assume that there are multiple HibernateSession instances at work here.

My question therefore is: how does Spring Data handle Hibernate Sessions? When does it open or close them? Is there a way to configure it to use the same session for the entire runtime of my application to make full use of Hibernate's object cache? Is there a reason not to do it that way?

Thanks,

Alan

Martin Häusler
  • 6,544
  • 8
  • 39
  • 66

1 Answers1

112

I think I've found the answer myself. If somebody finds this question, here's my answer.

How does Spring manage Hibernate Sessions?

By default, Spring Boot applies transaction management at the repository level. In this case, when calling a JpaRepository method (or in general any Repository method), Spring will:

  • Ask the SessionFactory to create a new session
  • Open this session
  • Open a transaction
  • Perform the called Repository method
  • Close the transaction
  • Close the session

However, if you apply @Transactional to the service class or method, Spring will open the session and the transaction on entry to the service method, and the repository method will be performed within the existing transaction.

What are the consequences?

As a programmer...

  • you do not need to concern yourself with transactions or sessions at all.
  • if you want to rely on Hibernate's caching functionality, you must specify @Transactional on a larger scope than the repository. Caching only works within the same HibernateSession.
  • you must decide the equivalence of your @Entity objects by their Hibernate ID value, rather than by using Java's == operator.
  • you need to take care that lazy collections (for example in an @OneToMany reference) in your @Entity classes (see FetchMode.LAZY as opposed to FetchMode.EAGER) are used exclusively within an @Transactional-annotated method

Also for reference, the following link has been quite helpful: Multiple Transactions in single session

As with many other aspects of Spring, there is a lot to be gained here, if you are willing to sacrifice direct control over your application.

Andrew Spencer
  • 15,164
  • 4
  • 29
  • 48
Martin Häusler
  • 6,544
  • 8
  • 39
  • 66
  • 14
    Well actually that isn't true… Depending on your transaction demarcation you will either reuse the already opened session. If you have a service method annotated with `@Transactional` (and have properly setup tx support) spring will open a `Session`/`EntityManager` and reuse it for all db calls you do inside that transaction. Also it should be noted that your service layer should be the transactional layer NOT your data access layer. – M. Deinum Sep 08 '14 at 06:56
  • @M.Deinum hi dinum, I'm new to spring boot. My question is also regarding to this. Do I need to use SessionFactory if I use jpaRepostitory? Does spring boot automatically handle session if multiple requests come? Hope I will be receiving your answer to my question. https://stackoverflow.com/questions/51764684/does-sessionfactory-or-entitymanager-use-with-jpa-repositories – varman Aug 10 '18 at 05:58
  • 1
    I made an edit to clarify the behaviour with default transaction demarcation on repository, vs annotating service method with `@Transactional` – Andrew Spencer Sep 24 '18 at 12:02
  • 8
    Also note that by default in a web application, Spring Boot will create an open-entitymanager-in-view which means that the Hibernate session (which is behind the EntityManager) lasts for the entire duration of HTTP request processing. Transaction will still be created at the point of entering `@Transactional` method, but will use the existing EntityManager. – Andrew Spencer Sep 24 '18 at 12:06
  • This answer is incorrect. Check @AndrewSpencer comment which is correct – ACV Sep 08 '20 at 10:31
  • @M.Deinum if I understand it correctly for a , e.g , JpaRepository, spring creates a HibernateSession but you cannot access , for example, the children of the entity that are lazily initialized, is it correct? – Andreea Oct 27 '21 at 20:05