Why doesn't openSession work but getCurrentSession works in Spring Hibernate
Asked Answered
A

1

4

I have written a sample Spring Hibernate application o understand how Spring hibernate integration works.

Here is my applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">

    <context:component-scan base-package="com.general" />

    <tx:annotation-driven />

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl" />
        <property name="username" value="system" />
        <property name="password" value="admin_123" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean ">
        <property name="dataSource" ref="dataSource"></property>
        <property name="packagesToScan" value="com.general"></property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
</beans>

Then, my service class is like that

package com.general;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;


@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService{

    @Autowired
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Transactional
    public void saveEmployee(Employee emp) {
        Session session = sessionFactory.getCurrentSession();//.openSession();
        session.save(emp);
    }

}

And my main class is

public class App {

    public static void main(String[] args) {
        System.out.println("load context");
        ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Employee em = new Employee();
        em.setId(1l);
        em.setName("John");

        EmployeeService emService = (EmployeeService) context.getBean("employeeService");
        emService.saveEmployee(em);
    }

}

If I run this application using getCurrentSession method, then it runs fine and employee is saved into the database but if i use openSession method, then no SQL query is fired and thus nothing is saved into the database.

I am not sure why this is happening. May be I don't have correct understanding of getCurrentSession () and openSession (). Can please someone let me know the reason behind it.

Aquinas answered 11/1, 2014 at 20:12 Comment(1)
possible duplicate of Hibernate openSession() vs getCurrentSession()Sculpture
K
12

The fact that you have @Transactional on a method in a @Service annotated class along with a TransactionManager means the whole transaction lifecycle will be managed by Spring.

When your saveEmployee method is called, Spring will open a Session, start a transaction, execute your code, commit the transaction and close the Session. The Session it starts is bound to the current thread and available through getCurrentSession().

If you instead use openSession(), you are opening a completely unrelated Session, not managed by Spring's TransactionManager. As such, the transaction won't be committed and the Sessionwon't be closed unless you do it yourself.

Kickoff answered 11/1, 2014 at 20:19 Comment(6)
if the session is closed at the end of a transaction, how can the same session (already closed) be reopened by another call of getCurrentSession() in the same thread?Surplusage
@Surplusage It doesn't. A new one is created and returned.Kickoff
thanks. If saveEmployee method is called twice from the same thread one after the other, there will be 2 different transactions, right? one for each call.Surplusage
@Surplusage I believe there will be two transactions, yes. But there might only be one Session.Kickoff
@SotiriosDelimanolis- How can there by only one session. Each transaction opens a new session..isn't it?Aquinas
@Aquinas I don't know about all implementations. But a SessionFactory may be pooling the Session objects per thread. It's been a long time and I haven't worked with Hibernate so I can't give you a positive answer.Kickoff

© 2022 - 2024 — McMap. All rights reserved.