dimanche 26 juin 2016

org.hibernate.HibernateException: No Session found for current thread 5

I know this problem is asked a lot but I am stuck. I am basing my project off of this tutorial: http://www.cavalr.com/blog/Spring_3_and_Annotation_Based_Hibernate_4_Example

This is my root-context.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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd">

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="${jdbc.driver}"/>
    <property name="jdbcUrl" value="${jdbc.url}"/>
    <property name="user" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="initialPoolSize" value="1" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="20" />
  </bean>

  <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
      <list>
        <value>classpath:db.properties</value>
      </list>
    </property>
  </bean>

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

    </property>
  </bean>

  <!-- Enables the Hibernate @Transactional programming model -->
  <tx:annotation-driven transaction-manager="transactionManager"/>

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

This is my servlet-context.xml

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

  <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
  <context:component-scan base-package="com.joe.recipes" />
  <!-- Enables the Spring MVC @Controller programming model -->
  <mvc:annotation-driven />

  <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
  <resources mapping="/resources/**" location="/resources/" />

  <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
  <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
  </beans:bean>

</beans:beans>

This is my AbstractDaoImpl

public abstract class AbstractDaoImpl<E, I extends Serializable> implements AbstractDao<E,I> {

    private Class<E> entityClass;

    protected AbstractDaoImpl(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    @Autowired
    private SessionFactory sessionFactory;

    public Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    @Override
    public E findById(I id) {
        return (E) getCurrentSession().get(entityClass, id);
    }

    @Override
    public void saveOrUpdate(E e) {
        getCurrentSession().saveOrUpdate(e);
    }

    @Override
    public void delete(E e) {
        getCurrentSession().delete(e);
    }

    @Override
    public List findByCriteria(Criterion criterion) {
        Criteria criteria = getCurrentSession().createCriteria(entityClass);
        criteria.add(criterion);
        return criteria.list();
    }
}

This is my RecipeDaoImpl class

@Repository
public class RecipeDaoImpl extends AbstractDaoImpl<Recipe, String> implements RecipeDao {

    protected RecipeDaoImpl() {
        super(Recipe.class);
    }

    @Override
    public boolean saveRecipe(Recipe r) {
        return saveRecipe(r);
    }

    @Override
    public Recipe getRecipe(String recipeId) {
        return findById(recipeId);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Recipe> findRecipes(String keyword) {
        return findByCriteria( Restrictions.and( Restrictions.like("name", keyword, MatchMode.ANYWHERE),
            Restrictions.like("keywords", keyword, MatchMode.ANYWHERE) ) );
    }
}

This is my RecipeServiceImpl class

@Service("recipeService")
@Transactional(readOnly = true)
public class RecipeServiceImpl implements RecipeService {
    @Autowired
    private RecipeDao recipeDao;

    @Override
    @Transactional(readOnly = false)
    public boolean saveRecipe(Recipe r) {
        return recipeDao.saveRecipe(r);
    }

    @Override
    public Recipe getRecipe(String recipeId) {
        return recipeDao.getRecipe(recipeId);
    }

    @Override
    public List<Recipe> findRecipes(String keyword) {
        return recipeDao.findRecipes(keyword);
    }
}

This is my RecipeController

/**
 * Handles requests for the application home page.
 */
@Controller
public class RecipeController {

    private static final Logger logger = LoggerFactory.getLogger(RecipeController.class);

    @Autowired
    private RecipeService recipeService;

    /**
     * Adds recipes to the DB
     */
    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add(Locale locale, Model model) {
        return "add";
    }

    /**
     * Searches for recipes
     */
    @RequestMapping(value = "/search", method = RequestMethod.POST)
    public String search(@RequestParam(value="keyword", required=true) String keyword, Model model) {

        List<Recipe> recipes = recipeService.findRecipes(keyword);
        System.out.println( "Results:"+ recipes.size() );
        return "results";
    }

    /**
     * Logs in the user
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public String login(Locale locale, Model model) {

        return "login";
    }
}

I've tried putting the @Transactional on the RecipeDaoImpl class and the AbstractDaoImpl class and neither worked.

EDIT: I fixed this by catching the exception and opening a new one:

public Session getCurrentSession() {
    Session session = null;
    try { 
        session = sessionFactory.getCurrentSession();
    } catch ( HibernateException he ) {
        session = sessionFactory.openSession();
    }
    return session;
}

Aucun commentaire:

Enregistrer un commentaire