0

Refer the following example.

@Repository
public class ContactDAOImpl implements ContactDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<Contact> findAll() {
        Session session = sessionFactory.openSession();
        return session.createQuery("from Contact").list();
    }
}

Before it gets invoked the session.openSession(), spring has already created a session for the thread via OpenEntityManagerInViewInterceptor.

Even if I close the session manually (considering the answer) as below

    @Override
    public List<Contact> findAll() {
        Session session;
        try{
            session = sessionFactory.openSession();
            return session.createQuery("from Contact").list();
        }finally{
            if(session!=null){
                session.close(); //logs says it is closed, but actually it gets closed via OpenEntityManagerInViewInterceptor, not by this call.
            }
        }
    }

still Spring holds the session and close it via OpenEntityManagerInViewInterceptor.

Appreciate very much if anyone explain me the use of Hibernate session in a Spring container.

And when to use openSession() and getCurrentSession() and when we should not use them?

Update:

Both the above examples are working fine. But why?

If I use the getCurrentSession() with the configuration spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext, it also works fine.

Update2:

Here is the log output I get, when I use session.openSession(). You will see at the end of the log, session (SessionImpl) is about to be closed.

2017-03-01 10:28:31.106 DEBUG 6008 --- [io-8080-exec-10] o.j.s.OpenEntityManagerInViewInterceptor : Opening JPA EntityManager in OpenEntityManagerInViewInterceptor
2017-03-01 10:28:31.106 TRACE 6008 --- [io-8080-exec-10] .i.SessionFactoryImpl$SessionBuilderImpl : Opening Hibernate Session.  tenant=null, owner=org.hibernate.jpa.internal.EntityManagerImpl@445e7f4a
2017-03-01 10:28:31.107 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Opened session at timestamp: 14883443111
2017-03-01 10:28:31.108 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Setting flush mode to: AUTO
2017-03-01 10:28:31.109 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Setting cache mode to: NORMAL
2017-03-01 10:28:31.110 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Found thread-bound EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@445e7f4a] for JPA transaction
2017-03-01 10:28:31.110 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Creating new transaction with name [com.sura2k.hbm.business.ContactServiceImpl.findAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
2017-03-01 10:28:31.111 DEBUG 6008 --- [io-8080-exec-10] o.s.jdbc.datasource.DataSourceUtils      : Setting JDBC Connection [ProxyConnection[PooledConnection[conn9: url=jdbc:h2:mem:contactsdb user=SA]]] read-only
2017-03-01 10:28:31.112 DEBUG 6008 --- [io-8080-exec-10] o.h.e.t.internal.TransactionImpl         : begin
2017-03-01 10:28:31.112 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : Preparing to begin transaction via JDBC Connection.setAutoCommit(false)
2017-03-01 10:28:31.112 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : Transaction begun via JDBC Connection.setAutoCommit(false)
2017-03-01 10:28:31.112 TRACE 6008 --- [io-8080-exec-10] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#afterBeginCallback
2017-03-01 10:28:31.113 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Setting flush mode to: MANUAL
2017-03-01 10:28:31.113 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle@34b8834a]
2017-03-01 10:28:31.114 TRACE 6008 --- [io-8080-exec-10] .i.SessionFactoryImpl$SessionBuilderImpl : Opening Hibernate Session.  tenant=null, owner=null
2017-03-01 10:28:31.116 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Opened session at timestamp: 14883443111
2017-03-01 10:28:31.116 TRACE 6008 --- [io-8080-exec-10] o.h.engine.query.spi.QueryPlanCache      : Located HQL query plan in cache (from ContactEntity)
2017-03-01 10:28:31.117 TRACE 6008 --- [io-8080-exec-10] o.h.engine.query.spi.QueryPlanCache      : Located HQL query plan in cache (from ContactEntity)
2017-03-01 10:28:31.117 TRACE 6008 --- [io-8080-exec-10] o.h.engine.query.spi.HQLQueryPlan        : Find: from ContactEntity
2017-03-01 10:28:31.117 TRACE 6008 --- [io-8080-exec-10] o.hibernate.engine.spi.QueryParameters   : Named parameters: {}
2017-03-01 10:28:31.118 DEBUG 6008 --- [io-8080-exec-10] org.hibernate.SQL                        : select contactent0_.contactid as contacti1_0_, contactent0_.email as email2_0_, contactent0_.name as name3_0_ from contact contactent0_
2017-03-01 10:28:31.119 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Registering statement [prep10: select contactent0_.contactid as contacti1_0_, contactent0_.email as email2_0_, contactent0_.name as name3_0_ from contact contactent0_]
2017-03-01 10:28:31.120 TRACE 6008 --- [io-8080-exec-10] o.h.e.jdbc.internal.JdbcCoordinatorImpl  : Registering last query statement [prep10: select contactent0_.contactid as contacti1_0_, contactent0_.email as email2_0_, contactent0_.name as name3_0_ from contact contactent0_]
2017-03-01 10:28:31.121 TRACE 6008 --- [io-8080-exec-10] org.hibernate.loader.Loader              : Bound [1] parameters total
2017-03-01 10:28:31.121 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Registering result set [rs23: org.h2.result.LocalResult@4e4e3165 columns: 3 rows: 0 pos: -1]
2017-03-01 10:28:31.121 TRACE 6008 --- [io-8080-exec-10] org.hibernate.loader.Loader              : Processing result set
2017-03-01 10:28:31.121 TRACE 6008 --- [io-8080-exec-10] org.hibernate.loader.Loader              : Done processing result set (0 rows)
2017-03-01 10:28:31.121 TRACE 6008 --- [io-8080-exec-10] org.hibernate.loader.Loader              : Total objects hydrated: 0
2017-03-01 10:28:31.122 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing statement [prep10: select contactent0_.contactid as contacti1_0_, contactent0_.email as email2_0_, contactent0_.name as name3_0_ from contact contactent0_]
2017-03-01 10:28:31.122 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Closing result set [rs23: org.h2.result.LocalResult@4e4e3165 columns: 3 rows: 0 pos: 0]
2017-03-01 10:28:31.122 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Closing prepared statement [prep10: select contactent0_.contactid as contacti1_0_, contactent0_.email as email2_0_, contactent0_.name as name3_0_ from contact contactent0_]
2017-03-01 10:28:31.123 TRACE 6008 --- [io-8080-exec-10] o.h.e.jdbc.internal.JdbcCoordinatorImpl  : Starting after statement execution processing [ON_CLOSE]
2017-03-01 10:28:31.123 TRACE 6008 --- [io-8080-exec-10] o.h.e.i.StatefulPersistenceContext       : Initializing non-lazy collections
2017-03-01 10:28:31.123 TRACE 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Triggering beforeCommit synchronization
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Triggering beforeCompletion synchronization
2017-03-01 10:28:31.124 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Initiating transaction commit
2017-03-01 10:28:31.124 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl@445e7f4a]
2017-03-01 10:28:31.124 DEBUG 6008 --- [io-8080-exec-10] o.h.e.t.internal.TransactionImpl         : committing
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#beforeCompletionCallback
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : SessionImpl#beforeTransactionCompletion()
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] .t.i.SynchronizationRegistryStandardImpl : SynchronizationRegistryStandardImpl.notifySynchronizationsBeforeTransactionCompletion
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : Preparing to commit transaction via JDBC Connection.commit()
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : Transaction committed via JDBC Connection.commit()
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : LogicalConnection#afterTransaction
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
2017-03-01 10:28:31.124 TRACE 6008 --- [io-8080-exec-10] j.i.AbstractLogicalConnectionImplementor : re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] cResourceLocalTransactionCoordinatorImpl : ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(true)
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] .t.i.SynchronizationRegistryStandardImpl : SynchronizationRegistryStandardImpl.notifySynchronizationsAfterTransactionCompletion(3)
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : SessionImpl#afterTransactionCompletion(successful=true, delayed=false)
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Triggering afterCommit synchronization
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Triggering afterCompletion synchronization
2017-03-01 10:28:31.126 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Setting flush mode to: AUTO
2017-03-01 10:28:31.127 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.JpaTransactionManager        : Not closing pre-bound JPA EntityManager after transaction
2017-03-01 10:28:31.132 DEBUG 6008 --- [io-8080-exec-10] o.j.s.OpenEntityManagerInViewInterceptor : Closing JPA EntityManager in OpenEntityManagerInViewInterceptor
2017-03-01 10:28:31.132 DEBUG 6008 --- [io-8080-exec-10] o.s.orm.jpa.EntityManagerFactoryUtils    : Closing JPA EntityManager
2017-03-01 10:28:31.132 TRACE 6008 --- [io-8080-exec-10] org.hibernate.internal.SessionImpl       : Closing session
2017-03-01 10:28:31.132 TRACE 6008 --- [io-8080-exec-10] o.h.e.jdbc.internal.JdbcCoordinatorImpl  : Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl@69c176d4]
2017-03-01 10:28:31.133 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
2017-03-01 10:28:31.133 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.LogicalConnectionManagedImpl   : Closing logical connection
2017-03-01 10:28:31.133 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.ResourceRegistryStandardImpl   : Releasing JDBC resources
2017-03-01 10:28:31.133 TRACE 6008 --- [io-8080-exec-10] o.h.r.j.i.LogicalConnectionManagedImpl   : Logical connection closed

Also I tried to monitor this using VisualVM Profiler. After making 5 requests to http://localhost:8080/contact, I was able to see only one instance of SessionImpl. enter image description here

Also I have uploaded a simpler version here https://bitbucket.org/sura2k/tests which I used to test.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
sura2k
  • 7,365
  • 13
  • 61
  • 80
  • 2
    It's simple: you never use openSession(). Calling getCurrentSession() returns the session bound to the current Spring transaction, which is what you want. And Spring closes it for you. – JB Nizet Feb 28 '17 at 12:15
  • @JB Thanks for the support. Yes I'm using getCurrentSession(). But can you explain the different between these 2. Even If I use openSession(), spring (boot) closes the session for me with the transaction. So both looks same, isn't it? – sura2k Feb 28 '17 at 12:28
  • I think your diagnostic is wrong, and that Spring does not close the session opened with openSession() at the end of the transaction. But anyway, you shouldn't use openSession() in the first place. – JB Nizet Feb 28 '17 at 13:02
  • @JBNizet I have no intention to use `openSession()`, but I'm confused with the behavior. If you can take a look at the my **Update2**, you will see a log saying it is going to be closed. Also I monitored this using Visual VM. I have added every detail to the end of the post. Appreciate very much If you can take a close look and tell me where I did wrong. – sura2k Mar 01 '17 at 05:20
  • In your logs, I see two "Opening session", and only one "Closing session". My analysis is that Spring opens one for you, then you open one in your own code, but don't close it, then Spring closes the one it has opened. – JB Nizet Mar 01 '17 at 06:59
  • @JBNizet I got your point. So changed it to `getCurrentSession()`. Logs looks fine, opens one session and closes one. But throws this error *No CurrentSessionContext configured!; nested exception is org.hibernate.HibernateException: No CurrentSessionContext configured!*. So I added this `spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext` as a config parameter in *application.properties*. Now it opens 2 sessions and closes 2 sessions at the end. Why Spring creates a redundant each time? Don't you think there is something fishy? – sura2k Mar 01 '17 at 07:21
  • You shouldn't have to do that if you properly configure Spring. The logs show you're using JPA. Then why do you even try using the Hibernate session? Use the JPA API: inject an EntityManager (with `@PersistenceContext`, and use it. As explained in the documentation. – JB Nizet Mar 01 '17 at 07:30
  • @JBNizet Thank you very much, got it... I have messed up. The additional one is actually the EntityManager (wrapped by session) instance automatically injected into the thread. – sura2k Mar 01 '17 at 07:37

0 Answers0