org.hibernate.HibernateException:找不到当前线程5的会话

时间:2014-04-26 18:25:38

标签: java spring hibernate

我知道这个问题很多,但我被困住了。我将我的项目从本教程开始:http://www.cavalr.com/blog/Spring_3_and_Annotation_Based_Hibernate_4_Example

这是我的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>

这是我的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>

这是我的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();
    }
}

这是我的RecipeDaoImpl班级

@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) ) );
    }
}

这是我的RecipeServiceImpl班级

@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);
    }
}

这是我的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";
    }
}

我已尝试将@Transactional放在RecipeDaoImpl班级和AbstractDaoImpl班级上,但都没有奏效。

编辑: 我通过捕获异常并打开一个新异常来解决这个问题:

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

2 个答案:

答案 0 :(得分:0)

它是什么意思&#34;既不起作用又#34 ;?你的问题是什么?

我认为您的问题是@EnableTransactionManagement,并且只在它们定义的相同应用程序上下文中查找bean上的@Transactional。这意味着,如果您在WebApplicationContext中为DispatcherServlet添加注释驱动配置,它只会检查@控制器中的事务bean,而不是您的服务。

在application-context.xml中尝试

<context:component-scan base-package="path.to.your.models, path.to.your.daos, path.to.your.services"/>

在servlet-context.xml中

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

另一个主题:Spring @transactional not working

答案 1 :(得分:0)

您的“修复”实际上是一个危险的修复,因为您正在Springs事务管理范围之外打开一个新会话。这最终将导致连接泄漏,内存问题和稳定性问题。

真正的问题是您的根上下文中有<tx:annotation-driven />,并且您要进行组件扫描DispatcherServlet加载的上下文。将<tx:annotation-driven />移到DispatcherServlet加载的上下文中以真正解决您的问题。

或将组件扫描分为2个,根上下文应扫描除控制器外的所有内容

<context:component-scan base-package="com.joe.recipes">
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</context:component-scan>

,并且调度程序servlet应该仅检测与Web相关的bean。

<context:component-scan base-package="com.joe.recipes" use-default-filters="false">
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 
</context:component-scan>

现在您可以将<tx:annotation-driven />留在原处了。