Pergunta

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.

Foi útil?

Solução

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.

Outras dicas

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.

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.

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

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.

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
    "

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>

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

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 .

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.

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;

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.

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

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top