Hibernate Spring ampq消费品-“;找不到当前线程的会话“;第一次尝试时出错
我有一个SpringMVC应用程序。我想使用springampq来执行异步任务。 我的REST后端使用@Transactional注释来管理事务。完成工作后,它将任务推送到呼气机,然后返回。然后,任务由使用者接收,使用者在第一次尝试时会收到“org.hibernate.HibernateException:No Session found for current thread”错误。然后spring ampq重试将任务发送给使用者,这次它可以正常工作,没有任何会话错误 我如何在第一次尝试时使此场景工作 我的spring ampq配置类似于此(): REST后端的代码与此类似:Hibernate Spring ampq消费品-“;找不到当前线程的会话“;第一次尝试时出错,hibernate,spring-mvc,transactions,spring-transactions,spring-amqp,Hibernate,Spring Mvc,Transactions,Spring Transactions,Spring Amqp,我有一个SpringMVC应用程序。我想使用springampq来执行异步任务。 我的REST后端使用@Transactional注释来管理事务。完成工作后,它将任务推送到呼气机,然后返回。然后,任务由使用者接收,使用者在第一次尝试时会收到“org.hibernate.HibernateException:No Session found for current thread”错误。然后spring ampq重试将任务发送给使用者,这次它可以正常工作,没有任何会话错误 我如何在第一次尝试时使此场
@Controller
@Transactional(readOnly = true)
@RequestMapping(value = { "/myController" })
public class MyController extends BaseController {
@Autowired
private RabbitTemplate exchangeTemplate;
@Transactional(readOnly = false)
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody MyClass update(@RequestBody MyClass myclass, HttpServletRequest request) throws Exception {
getAuthorizationManager().authorizeUserFromRequest(request);
List<MyClass> result = getDataProvider().update(myclass);
exchangeTemplate.convertAndSend("foo.Foo.update", myclass.getId())
return result;
}
}
@控制器
@事务(只读=真)
@RequestMapping(值={“/myController”})
公共类MyController扩展BaseController{
@自动连线
私有RabbitTemplate交换模板;
@事务(只读=假)
@RequestMapping(method=RequestMethod.POST)
public@ResponseBody MyClass update(@RequestBody MyClass MyClass,HttpServletRequest)引发异常{
getAuthorizationManager().AuthorizationUserFromRequest(请求);
列表结果=getDataProvider().update(myclass);
exchangeTemplate.convertAndSend(“foo.foo.update”,myclass.getId())
返回结果;
}
}
好的。现在我明白问题在哪里了。
您使用的是LocalSessionFactoryBean
,它基于SpringSessionContext
,反过来,它希望在ThreadLocal
中的事务资源中有一个SessionHolder
。但是,只要AMQP侦听器在自己的线程中工作,就没有任何钩子在事务资源中注册sessionFactory
。类似于SpringMVC的OpenSessionInViewFilter
尝试使用
hibernate.current_session_context_class = local
作为LocalSessionFactoryBean
的hibernateProperties
。
我从未使用过LocalSessionFactoryBean
。EE容器JNDI中的JTASessionFactory
始终适用于所有情况
更新:
好的,只要您可以使用MVC和AMQP Listener中相同的IDataProvider
,问题就在于CurrentSessionContext
,AMQP线程中没有currentSession
,您必须执行sessionFactory.openSession()
仅在currentSessionContext
中没有currentSession
的情况下,从IDataProvider
实现的代码手动执行。大概是这样的:
Session hibernateSession = null;
try {
hibernateSession = this.sessionFactory.getCurrentSession();
}
catch(HibernateException he) {
hibernateSession = this.sessionFactory.openSession();
}
当然,您可以编写onwSpringSessionContext
变量,并将该代码移动到currentSession()
我不明白为什么在您重试的第二次尝试中它会起作用。在我的测试案例中,它无论如何都失败了
假设在您的配置中有一些东西,它负责处理currentSession
,但您没有提到它
HTH问题原来是在sessionfactory的初始化中。我有一个静态getDao函数,SessionFactory实例也是静态的:
@Repository
public class DaoFactory {
private static SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
DaoFactory.sessionFactory = sessionFactory;
}
public static HibernateDaoBase getDao(Class<?> className) {
.
.
很抱歉,您尚未显示异常StackTrace。请加上你的听众的代码。也许没有理由添加
@Transactional
..@artem我已经用stacktrace错误和侦听器的代码更新了问题。如果没有@Transactional
,所有尝试都会失败。我已经查看了“hibernate.current_session_context_class”属性,但它似乎“local”不是它的有效值:[。但我理解您试图表达的观点。我的一个问题是,我使用Tomcat作为服务器,直到现在还没有在其中设置事务管理器。[尽管如此,我还是不明白为什么会话在第二次试验中会被绑定。那么这不会也失败吗?这个线程建议不要使用当前的会话上下文类,除非你使用JTA,不幸的是,我不是。[是的,我理解这个问题。我认为只有一种方法可以解决它:实现您自己的拦截器,类似于OpenSessionInViewInterceptor
,并将其与@Transactional
一起使用。我不确定我是否能够管理它。据我所知,拦截器需要“在事务资源中注册sessionFactory
“。我仍然无法理解为什么它在第二次尝试中注册,但在第一次尝试中没有注册。此外,由于OpenSessionInviewWinterCeptor是一个web请求拦截器,但这个新的拦截器不会,我需要熟悉AOP框架吗?不幸的是,我没有。
@Controller
@Transactional(readOnly = true)
@RequestMapping(value = { "/myController" })
public class MyController extends BaseController {
@Autowired
private RabbitTemplate exchangeTemplate;
@Transactional(readOnly = false)
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody MyClass update(@RequestBody MyClass myclass, HttpServletRequest request) throws Exception {
getAuthorizationManager().authorizeUserFromRequest(request);
List<MyClass> result = getDataProvider().update(myclass);
exchangeTemplate.convertAndSend("foo.Foo.update", myclass.getId())
return result;
}
}
hibernate.current_session_context_class = local
Session hibernateSession = null;
try {
hibernateSession = this.sessionFactory.getCurrentSession();
}
catch(HibernateException he) {
hibernateSession = this.sessionFactory.openSession();
}
@Repository
public class DaoFactory {
private static SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
@Autowired
public void setSessionFactory(SessionFactory sessionFactory) {
DaoFactory.sessionFactory = sessionFactory;
}
public static HibernateDaoBase getDao(Class<?> className) {
.
.
@Repository
public class DaoFactory {
@Autowired
private SessionFactory sessionFactory;
public HibernateDaoBase getDao(Class<?> className) {
.
.
@Repository
@EnableCaching
public class DataProvider implements IDataProvider {
@Autowired
private DaoFactory daoFactory;