133

I created an application with spring + hibernate, but I always get this error. This is my first application with hibernate, I read some guides but I can not solve this problem. Where am I doing wrong?

This is the code of my application

ott 05, 2014 4:03:06 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
Informazioni: Refreshing   org.springframework.context.support.ClassPathXmlApplicationContext@1eab16b: startup date  [Sun Oct 05 16:03:06 CEST 2014]; root of context hierarchy
ott 05, 2014 4:03:06 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
Informazioni: Loading XML bean definitions from class path resource [springConfig.xml]
ott 05, 2014 4:03:08 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
ott 05, 2014 4:03:08 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.6.Final}
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
ott 05, 2014 4:03:09 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
ott 05, 2014 4:03:09 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
ott 05, 2014 4:03:09 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Exception in thread "main" org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at coreservlets.StudentDAOImpl.create(StudentDAOImpl.java:19)
at coreservlets.MainApp.main(MainApp.java:14)

student.java

package coreservlets;

public class Student {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId(){return id;}//getId

    public void setId(Integer id){this.id=id;}//setId

    public String getName(){return name;}//getName

    public void setName(String name){this.name=name;}//setName

    public Integer getAge(){return age;}//getAge

    public void setAge(Integer age){this.age=age;}//setAge

}//Student

studentDAO.java

package coreservlets;

import org.hibernate.SessionFactory;

public interface StudentDAO {

    public void setSessionFactory(SessionFactory sessionFactory);

    public void create(String name,Integer age);

}//StudentDAO

StudentDAOImpl.java

package coreservlets;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class StudentDAOImpl implements StudentDAO {

    private SessionFactory sessionFactory;

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

    public void create(String name,Integer age){
        Session session=sessionFactory.getCurrentSession();
        Student student=new Student();
        student.setName(name);
        student.setAge(age);
        session.save(student);
    }//create

}//StudentDAOImpl

MainApp.java

package coreservlets;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

    public static void main(String[] args) {

        ApplicationContext context=new ClassPathXmlApplicationContext("springConfig.xml");

        StudentDAOImpl student=(StudentDAOImpl) context.getBean("studentDAOImpl");

        student.create("Alessandro", new Integer(33));


    }//main

}//MainApp

springConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

<context:annotation-config/>

<context:component-scan base-package="coreservlets"/>

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/spring_hibernate"/>
  <property name="username" value="root"/>
  <property name="password" value="password"/>
  <property name="initialSize" value="5"/>
  <property name="maxTotal" value="10"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
    <value>
            hibernate.dialect=org.hibernate.dialect.MySQLDialect
    </value>
</property>

</bean>

</beans>

sql

create table student
(
id integer not null auto_increment,
name varchar(20) not null,
age integer not null,
primary key(id)
);
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Alex
  • 2,075
  • 5
  • 27
  • 39
  • 4
    Did you try adding an @Transactional to your DAO create method? – John Oct 05 '14 at 14:31
  • 1
    You forgot to declare a HibernateTransactionManager, and to make the method using Hibernate transactional. – JB Nizet Oct 05 '14 at 14:33
  • @itachi is not correct, `sessionFactory.openSession()` the transaction will disable. Because they are not the same session. > Add the annotation @Transactional of spring in the class service @Patrikoko is correct! see this question: https://stackoverflow.com/questions/15620355/for-web-mvc-spring-app-should-transactional-go-on-controller-or-service example: `@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})` – nvnpnco Apr 19 '17 at 11:21

20 Answers20

248

You must enable the transaction support (<tx:annotation-driven> or @EnableTransactionManagement) and declare the transactionManager and it should work through the SessionFactory.

You must add @Transactional into your @Repository

With @Transactional in your @Repository Spring is able to apply transactional support into your repository.

Your Student class has no the @javax.persistence.* annotations how @Entity, I am assuming the Mapping Configuration for that class has been defined through XML.

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
  • 1
    Please,Can you write the code of the application because it doesn't works..This is my first application with Hibernate – Alex Oct 05 '14 at 14:59
  • 3
    Annotation equivalent of is @EnableTransactionManagement – Anand Rockzz Jan 04 '15 at 08:46
  • 8
    Also, make sure you use org.springframework.transaction.annotation.Transactional, not javax.persistance.Transactional – imnd_neel May 20 '16 at 10:44
  • 1
    I have tried for hours to get the transaction to work and finally i used @EnableTransactionManagement instead of and everything works perfectly. I cannot thank you enough Manuel – Abu Sulaiman Feb 27 '17 at 03:32
  • it is probably obvious, but still: @EnableTransactionManagement goes to your configuration class (that one annotated with @Configuration) – Jaroslav Záruba Mar 11 '18 at 21:40
  • 1
    This worked perfectly after adding both `@EnableTransactionManagement` and `@Transactional` to my DAO class. – Suresh Aug 12 '18 at 03:42
42

I have had the same issue, but in a class that was not a part of the service layer. In my case, the transaction manager was simply obtained from the context by the getBean() method, and the class belonged to the view layer - my project utilizes OpenSessionInView technique.

The sessionFactory.getCurrentSession() method, has been causing the same exception as the author's. The solution for me was rather simple.

Session session;

try {
    session = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
    session = sessionFactory.openSession();
}

If the getCurrentSession() method fails, the openSession() should do the trick.

itachi
  • 3,389
  • 2
  • 24
  • 29
  • when upgrading from Hibernate3 to Hibernate5, I had to change the code from SessionFactoryUtils.getSession() to sessionFactory.getCurrentSession(). Came across the same error at that time. – user811433 Jul 20 '16 at 20:54
  • 3
    This gives the really nasty behaviour that if `sessionFactory.getCurrentSession();` succeeds then the session should not be closed but if `sessionFactory.openSession();` succeeds it must be closed – Richard Tingle Oct 18 '17 at 15:41
  • 1
    Agree @RichardTingle. Seems like openSession is a hack to bypass the exception. What should be the idle solution for this? – Praveen Shendge Oct 11 '18 at 06:42
  • 1
    @Praveen what I actually did was have a service accept a lambda `Function` meaning "if I had a session I'd use it to do X". Then the method handles provisioning and (If neccissary) deprovisioning the session, and just returns the T. So external consumers of the service never actually get their hands on a session – Richard Tingle Oct 13 '18 at 21:49
  • This made my program run without sign of error. I am worried that I don’t have a transaction across multiple queries created this way, which means that I risk returning inconsistent results? – Ole V.V. Jul 13 '20 at 14:19
  • For me too many connections are opened and the application eventually dies. I used `netstat -nat | grep 3306` and I can see too many connections waiting for close. – mercury May 02 '22 at 07:53
  • This solution also leads to this problem: https://stackoverflow.com/a/33699600/14039503 – mercury May 03 '22 at 00:34
14

Add the annotation @Transactional of spring in the class service

Patrikoko
  • 478
  • 5
  • 5
5

I had this error too because in the file where I used @Transactional annotation, I was importing the wrong class

import javax.transaction.Transactional; 

Instead of javax, use

import org.springframework.transaction.annotation.Transactional; 
Daniel Puiu
  • 962
  • 6
  • 21
  • 29
browndoor
  • 68
  • 1
  • 8
3

In your xyz.DAOImpl.java

Do the following steps:

//Step-1: Set session factory

@Resource(name="sessionFactory")
private SessionFactory sessionFactory;

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

//Step-2: Try to get the current session, and catch the HibernateException exception.


//Step-3: If there are any HibernateException exception, then true to get openSession.

try 
{
    //Step-2: Implementation
    session = sessionFactory.getCurrentSession();
} 
catch (HibernateException e) 
{
    //Step-3: Implementation
    session = sessionFactory.openSession();
}
abc123
  • 17,855
  • 7
  • 52
  • 82
ArunDhwaj IIITH
  • 3,833
  • 1
  • 24
  • 14
3

You need to allow transaction to your DAO method. Add,

@Transactional(readOnly = true, propagation=Propagation.NOT_SUPPORTED)

over your dao methods. And @Transactional should be from the package:

org.springframework.transaction.annotation.Transactional
Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
RahuL Sharma
  • 478
  • 4
  • 8
2

I added these configuration in web.xml and it works well for me!

<filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
    <init-param>
        <param-name>flushMode</param-name>
        <param-value>AUTO</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Additionally, the most ranked answer give me clues to prevent application from panic at the first run.

何德福
  • 81
  • 3
2

My configuration was like this. I had a QuartzJob , a Service Bean , and Dao . as usual it was configured with LocalSessionFactoryBean (for hibernate) , and SchedulerFactoryBean for Quartz framework. while writing the Quartz job , I by mistake annotated it with @Service , I should not have done that because I was using another strategy to wire the QuartzBean using AutowiringSpringBeanJobFactory extending SpringBeanJobFactory.

So what actually was happening is that due to Quartz Autowire , TX was getting injected to the Job Bean and at the same time Tx Context was set by virtue of @Service annotation and hence the TX was falling out of sync !!

I hope it help to those for whom above solutions really didn't solved the issue. I was using Spring 4.2.5 and Hibernate 4.0.1 ,

I see that in this thread there is a unnecessary suggestion to add @Transactional annotation to the DAO(@Repository) , that is a useless suggestion cause @Repository has all what it needs to have don't have to specially set that @transactional on DAOs , as the DAOs are called from the services which have already being injected by @Trasancational . I hope this might be helpful people who are using Quartz , Spring and Hibernate together.

1

@Transactional =javax.transaction.Transactional. Put it just beside @Repository.

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Alter Hu
  • 739
  • 1
  • 7
  • 15
1

My solution was (using Spring) putting the method that fails inside another method that creates and commits the transaction.

To do that I first injected the following:

@Autowired
private PlatformTransactionManager transactionManager;

And finally did this:

public void newMethod() {
    DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
    TransactionStatus transaction = transactionManager.getTransaction(definition);

    oldMethod();

    transactionManager.commit(transaction);
}
Aliuk
  • 1,249
  • 2
  • 17
  • 32
0

I encountered the same problem and finally found out that the <tx:annotaion-driven /> was not defined within the [dispatcher]-servlet.xml where component-scan element enabled @service annotated class.

Simply put <tx:annotaion-driven /> with component-scan element together, the problem disappeared.

Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Lee
  • 1
0

My similar issue got fixed with below 2 approaches.

1) Through manually handling transactions:

Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
UserInfo user = (UserInfo) session.get(UserInfo.class, 1);
tx.commit();

2) Tell Spring to open and manage transactions for you in your web.xml filters and Ensure to use @Repository @Transactional:

<filter>
  <filter-name>hibernateFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
  <init-param>
    <param-name>sessionFactory</param-name>
    <param-value>session.factory</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>hibernateFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
Jajikanth pydimarla
  • 1,512
  • 13
  • 11
0

Add transaction-manager to your <annotation-driven/> in spring-servlet.xml:

<tx:annotation-driven transaction-manager="yourTransactionBeanID"/>
Majid
  • 13,853
  • 15
  • 77
  • 113
0

Check your dao class. It must be like this:

Session session = getCurrentSession();
Query query = session.createQuery(GET_ALL);

And annotations:

@Transactional
@Repository
Evgeniya O
  • 41
  • 4
0

In this class above @Repository just placed one more annotation @Transactional it will work. If it works reply back(Y/N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO
Ihor Patsian
  • 1,288
  • 2
  • 15
  • 25
  • 1
    Welcome to SO. Kindly go through [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). In SO there is no custom of replying Y/N. If your answer works for the person they'll mark is as accepted. A helpful answer might be upvoted also. – Sri9911 Sep 30 '19 at 06:35
0

Thanks for comment of mannedear. I use springmvc and in my case I have to use as

@Repository
@Transactional
@EnableTransactionManagement
public class UserDao {
...
}

and I also add spring-context to pom.xml and it works

Lam
  • 1
0

I had the same issue. I resolved it doing the following:

  1. Add the this line to the dispatcher-servlet file:

    <tx:annotation-driven/>
    

    Check above <beans> section in the same file. These two lines must be present:

    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation= "http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
    
  2. Also make sure you added @Repository and @Transactional where you are using sessionFactory.

    @Repository
    @Transactional
    public class ItemDaoImpl implements ItemDao {
        @Autowired
        private SessionFactory sessionFactory;
    
Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
0

My Database table has mismatch column name with the Java Object (@Entity) which leads to throw the above exception.

By updating the table with appropriate column name resolves this issue.

VNT
  • 934
  • 2
  • 8
  • 19
0

In my case the problem was a Controller trying to access directly to a DAO with @Repository. Adding an @Service layer on top of the @Repository fixed the problem

tbotalla
  • 119
  • 2
  • 10
0

I had the similar issue which got resolved after adding @Transactional and @EnableTransactionManagement in the class where I was using HibernateTransactionManager. Please refer this link for further details:

https://www.baeldung.com/no-hibernate-session-bound-to-thread-exception

hirahul
  • 1
  • 1