18

I'm trying to set up my project using Spring 3.1 and Hibernate 4. I've been following some tutorials online. I'm getting a strange error that according to the spring forums should have been fixed with Spring 3.1. Spring Bug Tracker

When my service calls getCurrentSession(), it throws the following exception:

org.hibernate.HibernateException: **No Session found for current thread**] with root cause org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97) at
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:881)

****EDIT: updated my spring-dao.xml according to the Spring Spring 3.1 Documentation for Transactions. I've tried swapping out my datasource with a org.apache.commons.dbcp.BasicDataSource. Are there any properties I am missing from my configuration that could be causing this? ****

Here's my spring-dao.xml:

 <!-- Enable annotation style of managing transactions -->
<tx:annotation-driven transaction-manager="transactionManager" />   

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

<!-- Declare a datasource that has pooling capabilities-->   
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
            destroy-method="close"
            p:driverClass="${app.jdbc.driverClassName}"
            p:jdbcUrl="${app.jdbc.url}"
            p:user="${app.jdbc.username}"
            p:password="${app.jdbc.password}"
            p:acquireIncrement="5"
            p:idleConnectionTestPeriod="60"
            p:maxPoolSize="100"
            p:maxStatements="50"
            p:minPoolSize="10" />

<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" 
            p:sessionFactory-ref="sessionFactory" />

My User bean (User.java)

package com.foo.lystra.beans;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="users")
public class User implements Serializable {
private static final long serialVersionUID = -5527566191402296042L;

@Id
@Column(name = "idusers")
private Integer user_id;

@Column(name="login_name")
private String loginName;

@Column(name="password")
private String password;

@Column(name="role")
private String role;

@Column(name="congregation_id")
private Integer congregation_id;

public Integer getUser_id() {
    return user_id;
}
public void setUser_id(Integer user_id) {
    this.user_id = user_id;
}
public String getLoginName() {
    return loginName;
}
public void setLoginName(String loginName) {
    this.loginName = loginName;
}
public String getPassword() {
    return password;
}
public void setPassword(String password) {
    this.password = password;
}
public String getRole() {
    return role;
}
public void setRole(String role) {
    this.role = role;
}
public Integer getCongregation_id() {
    return congregation_id;
}
public void setCongregation_id(Integer congregation_id) {
    this.congregation_id = congregation_id;
}

public String toString() {
    return "user_name: " + this.loginName + " congregation_id: " + this.congregation_id.toString();
}
}

And finally my service...

package com.foo.lystra.services;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.foo.lystra.beans.User;
import com.foo.lystra.beans.Congregation;

@Service("congregationUserService")
@Transactional
public class CongregationUserService {
protected static Log logger = LogFactory.getLog(CongregationUserService.class);

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

public List<User> getAllUsers() {
    logger.debug("getting all users");

            //Exception is thrown on this next line:
    Session session = sessionFactory.getCurrentSession();

    Query query = session.createQuery("FROM users");
    return query.list();
}
}

I realize that my datasource is probably not getting used. If I have forgotten to include any configurations I can update this post. Also if the Tomcat startup logs are needed I can provide them as well.

Manuel
  • 3,828
  • 6
  • 33
  • 48
It Grunt
  • 3,300
  • 3
  • 21
  • 35
  • Do you have CGLIB on your classpath? Your Service doesn't implement any interfaces and so cannot use dynamic proxies to apply your Transactional behaviour. – Alex Barnes Jan 13 '12 at 08:28
  • From the tutorial I was following, it didn't look like i needed to go through the trouble of implementing a separate DAO/impl package. I was really hoping to be able to do everything straight from my services layer – It Grunt Jan 13 '12 at 16:02
  • Ok, but in order to weave the transactions around your methods without using interfaces you'll need to provide CGLIB. – Alex Barnes Jan 13 '12 at 16:19
  • This is covered in the docs here: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations – Alex Barnes Jan 13 '12 at 16:22
  • so if I am understanding the docs correctly, I've created the interface for the service and CongregationUserService now implements that interface. I've also added: However I'm still getting the same error – It Grunt Jan 13 '12 at 19:36
  • 1
    Can you also post code of invoking `CongregationUserService.getAllUsers()` method – Pokuri Jan 18 '12 at 07:05
  • how is CongregationUserService.getAllUsers() invoked? Is it being invoked from the spring security context? – Boris Treukhov Jan 21 '12 at 23:01
  • btw hibernate template is not deprecated, one of the reasons to use declarative approach and call getsession directly is that it eliminates the dependence of your persistence logic on spring i.e. it will depend on hibernate instead of spring + hibernate – Boris Treukhov Jan 21 '12 at 23:11
  • p.s. what I don't like in declarative approach is that it actually requests writing some tests to check that transactional annotation is in place and working - it's very easy to forget that tiny annotation and to get a connection leak or something like that – Boris Treukhov Jan 21 '12 at 23:17

14 Answers14

12

I have the same problem in a web application. The problem is with which exist in both configuration files: application-context.xml and webmvc-context.xml. The webmvc-context.xml is loaded after application-context.xml. I think the DAO class is loaded first with transactional references when the application-context.xml is loaded, but it is replace with another object, without transactional references, when webmvc-context.xml is loaded. Any way, I resolve the problem with specific packages scanned:
<context:component-scan base-package="com.app.repository" />
for application-context.xml, and
<context:component-scan base-package="com.app.web" />
for webmvc-context.xml.

Vali
  • 121
  • 1
  • 2
  • Useful answer. I just ran into this problem when rearranging some code. The multiple Spring application contexts can be confusing! – Alex Barnes Nov 04 '12 at 04:21
  • Goodness, I hope I still have the source code to try this out... I am just seeing this answer now. – It Grunt Feb 27 '13 at 17:10
6

I had this problem with spring-4.0.6 and hibernate-4.3.6.

Solution is to move all annotation-driven, component-scan, annotation-driven directives from root-context.xml to servlet-context.xml:

<mvc:annotation-driven />
<context:component-scan base-package="ru.dd.demo" />
<tx:annotation-driven transaction-manager="transactionManager" />

dataSource, sessionFactory and transactionManager can be still defined at root-context.xml.

user3418209
  • 76
  • 1
  • 2
2

Is it a web application? If so consider using OpenSessionInViewFilter. Cause I believe when using currentSession (which is bound to current thread) there must be a point in the code that unbinds the session from the thread.

I'm not sure whether transaction manager does this or not.

Amir Pashazadeh
  • 7,170
  • 3
  • 39
  • 69
2

I had the same error as yours.

This is a bug which is not solved yet.

https://jira.springsource.org/browse/SPR-9028

Try to change hibernate jar files to 3.6. because Spring uses it.

http://mvnrepository.com/artifact/org.springframework/spring-orm/3.1.0.RELEASE

here Spring 3.1 artifact and dependencies

erencan
  • 3,725
  • 5
  • 32
  • 50
1

As stated in Spring Reference (3.2.x):

In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.

So Beans defined or scanned with <context:component-scan> will be visible in your controllers so you can @Autowired them, but will be not visible in other applicationContext* files, so unless <tx:annotation-driven/> has been not defined in DispatcherServlet's config, @Transactional won't work.

So I'm guess that probably you have a <context:component-scan> in your DispatcherServlet's config and <tx:annotation-driven/> declaration in you applicationContext*.xml, so @Autowired works fine, but @Transactional is not.

Mateusz Szulc
  • 1,734
  • 19
  • 18
1

I had the same issue and tested all the answered solutions. Vali's answer was very helpful. What worked for me, was moving these beans from applicationContext.xml into web-servlet.xml:

<bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>       
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

Also, you need to add in web-servlet.xml:

xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"

xsi:schemaLocation="       
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    "
Adrian Cosma
  • 467
  • 8
  • 10
1

Add a OpenSessionInViewFilter filter in your web.xml

<filter>
    <filter-name>hibernateFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>hibernateFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>
punseti
  • 514
  • 4
  • 4
0

Had exactly the same error and it was solved by just creating an interface for my service. So in your case, I would create:

public interface ICongregationUserService {
   public List<User> getAllUsers();
}

then change CongregationUserService to implement it:

@Service("congregationUserService")
@Transactional
public class CongregationUserService implements ICongregationUserService{
   //...
}

and where you autowired CongregationUserService, autowire ICongregationUserService instead:

@Autowired
private ICongregationUserService congregationUserService;
Walid
  • 1,262
  • 11
  • 10
0

I solved this problem by putting <tx:annotation-driven transaction-manager="miTransactionManager"/> in the dispatcher-servlet.xml instead of any other xml config file.

I think this way allows beans to coexist in same spring context.

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
Dani
  • 4,001
  • 7
  • 36
  • 60
0

I've found that this issue is a bug of spring

this link https://jira.springsource.org/browse/SPR-9020 reports the problem..

to fix it I've used the Matias Mirabelli's workaround which can be found on this link https://gist.github.com/seykron/4770724

what is happening is that methods annotated with Propagation.SUPPORTS supports transaction but if there is no transactions bound to the thread the spring instead of create a new session it throws an HibernateException

in order to configure the sollution you can use the hibernate property:

hibernate.current_session_context_class = com.your.package.TransactionAwareSessionContext

thiagoh
  • 7,098
  • 8
  • 51
  • 77
  • I am not sure if this is the same issue. He annotated his service class with @Transactional at the class level with no annotation configuration. This means that whenever he calls one of the methods of this service from a Spring managed bean, it should spawn a transaction with PROPAGATION_REQUIRED (if no existing transaction is present), which is the default propagation mode. Please correct me if I am mistaken. – mess Dec 13 '13 at 22:57
  • I already answered a question related to this particular issue that you are mentioning in http://stackoverflow.com/questions/10181807/spring-3-1-hibernate-4-1-propagation-supports-issue/. – mess Dec 13 '13 at 22:58
0

I put

<context:component-scan base-package="com.sprhib.repo"/>  #(some class files are annotaed by @Repository,@Service,@Component)
<tx:annotation-driven transaction-manager="txManager" />
<task:annotation-driven/>

int the root.xml.

And I put

<context:component-scan base-package="com.sprhib.web"/>  #(some class files are annotaed by @Controller)
<mvc:annotation-driven />

int the servlet-context.xml.

It works.

陈俊杰
  • 41
  • 3
0

Not sure but the problem could be in p:packagesToScan. Your ConfigurationUserService is in package com.foo.lystra.services but p:packagesToScan has com.foo.lystra.beans

Gaurav
  • 1,549
  • 2
  • 15
  • 31
  • The packages to scan property in the session factory configuration refers to the location that mapped entities can be found. – Alex Barnes Jan 13 '12 at 08:19
0

Your configuration does not point to the annotated classes . Add them

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

  <property name="annotatedClasses">
    <list>
      <value>test.package.Foo</value>
      <value>test.package.Bar</value>
    </list>
  </property>
</bean>

It is similar to AnnotationSessionFactoryBean which was there earlier . Check the Api here .

Aravind A
  • 9,507
  • 4
  • 36
  • 45
0

I believe you need:

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

Otherwise the spring context will not find your service, thus won't wrap your methods with the Transactional aspects.

jonnysamps
  • 1,067
  • 1
  • 14
  • 20