【问题标题】:Hibernate could not obtain transaction-synchronized Session for current thread on remote serverHibernate 无法获取远程服务器上当前线程的事务同步会话
【发布时间】:2017-01-28 19:21:02
【问题描述】:

我阅读了有关类似问题的其他答案,但我还没有找到解决问题的方法。我有一个 Tomcat7 服务器和一个 Spring 应用程序,它使用 Hibernate 连接到我的 PostgreSQL 远程数据库。

我的框架版本是:
Spring框架4.2.2
Spring 安全 3.2.5
休眠 4.3.6

当我在本地主机上运行我的应用程序时,一切都很好,但是当我将它部署到我的服务器上时,我在登录时收到此错误:

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
    org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
    org.myapp.spring.dao.generic.GenericDAOImpl.getSession(GenericDAOImpl.java:59)
    org.myapp.spring.dao.impl.DeveloperDaoImpl.findByUsername(DeveloperDaoImpl.java:51)
    org.myapp.spring.service.impl.DeveloperServiceImpl.findByUsername(DeveloperServiceImpl.java:149)
    org.myapp.spring.web.security.UserDetailsServiceImpl.loadUserByUsername(UserDetailsServiceImpl.java:23)
    org.myapp.spring.web.security.MyAuthenticationProvider.authenticate(MyAuthenticationProvider.java:30)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)

我有两个初始化文件:

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        Class[] config = {AppConfig.class};
        return config;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        Class[] config = {SecurityConfig.class, HibernateConfig.class};
        return config;
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

@Component
public class SecurityWebApplicationInizializer extends AbstractSecurityWebApplicationInitializer {
}

还有三个配置文件:

@EnableWebMvc
@ComponentScan({ "org.myapp.spring.*" })
@EnableTransactionManagement
@PropertySource(value="classpath:myapp.properties")
public class AppConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {

    @Autowired
    private TokenInterceptor tokenInterceptor;
    private ApplicationContext applicationContext;
    private static final String UTF8 = "UTF-8";

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor);
    }

//other methods
}

@Configuration
@EnableWebSecurity
@EnableTransactionManagement
@ComponentScan("org.myapp.spring.web.security")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired private MyAuthenticationProvider authProvider;
@Autowired private UserDetailsService userDetailsService;

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authProvider);
    auth.userDetailsService(userDetailsService);
}

@Override
public void configure(WebSecurity web) throws Exception {
    DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
    handler.setPermissionEvaluator(permissionEvaluator());
    web.expressionHandler(handler);
}

@Bean
public PermissionEvaluator permissionEvaluator() {
    return new MyPermissionEvaluator();
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().and()
    .formLogin().loginPage("/html/login").defaultSuccessUrl("/html/index", true).permitAll()
    .and()
    .logout().logoutUrl("/html/logout").logoutSuccessUrl("/html/login?logout").invalidateHttpSession(true).clearAuthentication(true).permitAll()
    .and()
    .authorizeRequests()
    .antMatchers("/html/forbidden").permitAll()
    .antMatchers("/html/logistic").permitAll()
    .antMatchers("/html/ajax/logistic").permitAll()
    .antMatchers("/html/res/**").permitAll()
    .antMatchers("/html").authenticated()
    .antMatchers("/html/**").authenticated()
    .and()
    .exceptionHandling().accessDeniedPage("/html/forbidden");
}
}

最后:

@Configuration
@EnableTransactionManagement
@ComponentScan({ "org.myapp.spring.configuration" })
@PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfig {

@Autowired
private Environment environment;

@Bean
public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean  sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    sessionFactory.setPackagesToScan(new String[] { "org.myapp.spring.model"});
    sessionFactory.setHibernateProperties(hibernateProperties());

    try {
        sessionFactory.afterPropertiesSet();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return sessionFactory;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("hibernate.connection.driver_class"));
    dataSource.setUrl(environment.getRequiredProperty("hibernate.connection.url"));
    dataSource.setUsername(environment.getRequiredProperty("hibernate.connection.username"));
    dataSource.setPassword(environment.getRequiredProperty("hibernate.connection.password"));
    return dataSource;
}

private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
    return properties;
}

@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(s);
    return txManager;
}
}

GenericDaoImpl 是:

@Repository
public abstract class GenericDAOImpl<T> implements DAO<T> {

    @Autowired
    private SessionFactory sessionFactory;

protected Session getSession() {
            return sessionFactory.getCurrentSession();
        }
}

每个 DAO 都扩展了这个类,并有自己的 @Repository 注解。

每个服务都被注释为@transactional。这是 UserDetailsS​​ervice 的实现:

@Service
@Transactional
public class UserDetailsServiceImpl implements UserDetailsService, MyUserDetailsService {

    @Autowired private DeveloperService devService;
    @Autowired private AuthorizationService authorizationService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(username == null) {
            throw new UsernameNotFoundException("User not found");
        }
        Developer dev = devService.findByUsername(username);

        if(dev == null) {
            throw new UsernameNotFoundException("User not found");
        }
        MyUserDetails user = new MyUserDetails();
        user.setUsername(dev.getUsername());
        user.setPassword(dev.getPassword());
        user.setMaxAuthorityByIndex(dev.getRole());
        return user;
    }

我真的不知道这会是什么。也许服务器上的配置错误?对我来说,这似乎是正确的......

【问题讨论】:

  • 问题是您的服务有 2 个实例...未使用带有事务的实例。您正在对不同配置中的太多东西进行组件扫描,但不要这样做。您的安全和休眠配置也应该是根配置的一部分。 servlet 配置应该只包含与 web 相关的东西(控制器、视图和基础设施)。
  • 所以你是说我应该只使用一个配置文件?
  • 不,我不是...我是说您应该小心使用组件扫描的对象和位置,并且正确类型的类应该由正确的组件加载。理想情况下,ContextLoaderListener 应该包含基础设施服务,例如 DataSourceEntityManagerFactory,还包括服务、存储库等。您的 DispatcherServlet 应该反过来包含与 Web 相关的内容 @EnableWebMvc 以及控制器、视图等内容,但不包含服务。
  • 您的 DeveloperService 中是否有 @Transactional 注释?如果没有,请放在那里再试一次..
  • 任何解决方案都有效,我现在有同样的问题。我在所有 DAO 方法中都有 @Transactional。我在 stackoverflow 中尝试了许多其他解决方案仍然无法正常工作

标签: spring postgresql hibernate spring-mvc transactions


【解决方案1】:

将此添加到您的

    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("current_session_context_class","org.springframework.orm.hibernate4.SpringSessionContext");
        return properties;
    }

【讨论】:

  • 这不起作用,我使用 spring 5 的任何其他解决方案,休眠 5
猜你喜欢
  • 2015-02-04
  • 2017-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 2015-04-11
  • 2014-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多