Java org.hibernate.HibernateException: 没有找到当前线程 5 的会话
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23314894/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
org.hibernate.HibernateException: No Session found for current thread 5
提问by javajoe316
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
我知道这个问题经常被问到,但我被卡住了。我的项目基于本教程:http: //www.cavalr.com/blog/Spring_3_and_Annotation_Based_Hibernate_4_Example
This is my root-context.xml
这是我的 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
这是我的 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
这是我的 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
这是我的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) ) );
}
}
This is my RecipeServiceImpl
class
这是我的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);
}
}
This is my RecipeController
这是我的 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.
我试过把它@Transactional
放在RecipeDaoImpl
课堂上和AbstractDaoImpl
课堂上,但都没有奏效。
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;
}
回答by alfcope
What does it mean "neither worked"? What's your problem?
“都没有用”是什么意思?你怎么了?
I think your problem is @EnableTransactionManagement and only looks for @Transactional on beans in the same application context they are defined in. This means that, if you put annotation driven configuration in a WebApplicationContext for a DispatcherServlet, it only checks for @Transactional beans in your controllers, and not your services.
我认为您的问题是 @EnableTransactionManagement 并且只在定义它们的相同应用程序上下文中的 bean 上查找 @Transactional。这意味着,如果您将注释驱动的配置放在 DispatcherServlet 的 WebApplicationContext 中,它只会检查 @Transactional bean您的控制器,而不是您的服务。
Try, in your application-context.xml
试试,在你的 application-context.xml
<context:component-scan base-package="path.to.your.models, path.to.your.daos, path.to.your.services"/>
In your servlet-context.xml
在你的 servlet-context.xml
<context:component-scan base-package="com.springhibernatejpatest.controllers"/>
Another thread: Spring @transactional not working
回答by M. Deinum
Your "fix" is actually a dangerous one, as you are opening a new session outside the scope of Springs transaction management. This will eventually leave to connection leaks, memory issues and stability issues.
您的“修复”实际上是危险的,因为您正在打开 Springs 事务管理范围之外的新会话。这最终会导致连接泄漏、内存问题和稳定性问题。
The real problem is that you have <tx:annotation-driven />
in your root context and you do component scanning the context loaded by the DispatcherServlet
. Move the <tx:annotation-driven />
to the context loaded by the DispatcherServlet
to really fix your problem.
真正的问题是您<tx:annotation-driven />
在根上下文中执行组件扫描DispatcherServlet
. 将 移至<tx:annotation-driven />
加载的上下文DispatcherServlet
以真正解决您的问题。
Or split component-scanning into 2, the root context should scan everything but your controller
或者将组件扫描拆分为 2,根上下文应该扫描除控制器之外的所有内容
<context:component-scan base-package="com.joe.recipes">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
, and the dispatcher servlet one should detect only web related beans.
,并且调度程序 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>
Now you can leave the <tx:annotation-driven />
where it is.
现在你可以离开<tx:annotation-driven />
它所在的地方了。