安卓休眠唤醒ajax休线程,休眠无法获得远程服务器上当前线程的事务同步会话...

我在类似问题上阅读了其他答案,但我没有找到解决我的问题的方法。我有一个Tomcat7服务器和一个使用Hibernate连接到我的PostgreSQL远程数据库的Spring应用程序。 我的框架版本: Spring框架4.2.2 春季安全3.2.5 的Hibernate 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)

我有两个inizializer文件:

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 implements DAO {

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

}

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

2016-09-20

zuno

+0

的问题是,你有你的服务的两个实例...不使用与交易的一个。您在不同的配置中对太多东西进行组件扫描不这样做。您的安全性和休眠配置也应该是根配置的一部分。 servlet配置应该只包含web相关的东西(控制器,视图和基础设施)。 –

+0

所以你说我应该只使用一个配置文件? –

+0

不,我不是......我说你应该小心使用组件扫描的内容和位置,并且适当类型的类应该由适当的组件加载。 'ContextLoaderListener'理想情况下应该包含像'DataSource','EntityManagerFactory'等基础设施服务,但也包含服务,存储库等。您的DispatcherServlet应该包含Web相关的东西'@EnableWebMvc',以及诸如控制器,视图但没有服务。 –

<think>好的,我现在需要帮助用户解决在Delphi UniGUI中调用阻塞方法失败的问题。首先,我得理解UniGUI的基本架构和运行机制。UniGUI是一个用于开发Web应用的Delphi框架,它基于事件驱动的模型,类似于VCL,但运行在HTTP服务器环境中。 用户提到调用阻塞方法失败,可能涉及到主线程被阻塞的问题。因为在Web应用中,主线程负责处理HTTP请求和用户界面更新,如果主线程被长时间阻塞,会导致应用无响应或超时。我需要验证这一点,比如当执行一个长时间循环或同步操作时,界面是否冻结,或者请求是否超时。根据引用[3],用户之前使用WinExec执行批处理并休眠等待,这在UniGUI中如果直接在主线程调用,会导致同样的问题。 接下来,解决方案方面,异步处理是关键。用户需要使用线程来执行阻塞操作,避免主线程被占用。Delphi中的TThread类可以创建后台线程,处理完后再同步回主线程更新界面。例如,使用TThread.CreateAnonymousThread来创建匿名线程,在Execute方法中执行耗时操作,然后用Synchronize或Queue方法更新UI,这样就不会阻塞主线程。 另外,UniGUI可能提供了自己的异步机制,比如UniSession.AddJS或回调函数。用户可以在线程完成后,通过这些方法通知前端更新状态。例如,在匿名线程中执行完操作后,调用UniSession.AddJS('ajaxRequest(...)')触发前端的事件处理,从而更新页面内容。 还需要考虑使用定时器(UniTimer)进行轮询,适用于需要持续检查任务进度的场景。主线程启动任务后,定时器定期检查状态,避免长时间阻塞。同时,设置合理的超时和错误处理机制,比如在长时间无响应时取消任务,并提示用户。 在代码示例方面,给出一个使用匿名线程的示例,展示如何将阻塞操作移到后台,并通过Synchronize更新UI。同时,提醒用户避免在Synchronize中执行耗时操作,保持UI响应。另外,UniGUI的Session保持活动状态也很重要,防止长时间任务导致Session超时,可能需要调整服务器配置或发送心跳请求。 最后,总结原因和解决方案,确保用户理解主线程阻塞的影响,以及如何通过异步处理、线程和UniGUI特定方法解决问题。还要考虑用户的开发环境,比如引用[1]中的路径可能涉及第三方库,需确认线程安全;引用[3]的批处理调用方式在UniGUI中需要调整为异步执行,避免休眠导致的主线程挂起。</think>### Delphi UniGUI调用阻塞方法失败的原因及解决方案 #### 一、失败原因分析 1. **主线程阻塞导致无响应** UniGUI基于HTTP服务器事件模型,主线程负责处理用户请求和界面更新。若调用阻塞方法(如长时间循环、同步I/O操作),会导致主线程被占用,表现为: - 界面冻结无法更新 - HTTP请求超时(默认30秒) - 服务器日志出现`EUniSessionException`异常[^3] 2. **会话超时限制** UniGUI默认会话超时时间为30分钟,长时间阻塞操作可能导致会话提前终止[^1]。 3. **异步处理机制缺失** 直接调用如`Sleep()`,`ReadLn()`等同步方法,未采用UniGUI的异步处理模式。 #### 二、解决方案 ##### 1. 使用线程处理阻塞操作(推荐) ```delphi // 创建匿名线程执行耗时任务 procedure TMainForm.UniButton1Click(Sender: TObject); begin TThread.CreateAnonymousThread( procedure var ResultData: string; begin // 执行阻塞操作(示例:耗时计算) ResultData := DoLongTask(); // 通过同步方法更新UI TThread.Synchronize(nil, procedure begin UniLabel1.Caption := '结果:' + ResultData; end); end ).Start; end; ``` *注意:Synchronize内避免嵌套耗时操作* ##### 2. 使用UniGUI异步回调 ```delphi // 前端JavaScript发起异步请求 procedure TMainForm.UniButton2Click(Sender: TObject); begin UniSession.AddJS('ajaxRequest('+UniButton2.JSName+', "longtask", []);'); end; // 处理异步回调 procedure TMainForm.UniButton2AjaxEvent(Sender: TObject; EventName: string; Params: TUniStrings); begin if EventName = 'longtask' then TThread.CreateAnonymousThread( procedure begin // 执行阻塞操作 var res := DoLongTask(); UniSession.AddJS('alert("完成结果:' + res + '")'); end ).Start; end; ``` ##### 3. 配置优化 ```delphi // 调整会话超时时间(ServerModule自定义设置) initialization UniServerModule.SessionTimeout := 120; // 单位:分钟 // 心跳保持机制 procedure TMainForm.UniTimer1Timer(Sender: TObject); begin UniSession.KeepAlive; end; ``` #### 三、注意事项 1. **线程安全规范** - VCL组件操作必须通过`TThread.Synchronize` - 使用`CriticalSection`保护共享资源 - UniGUI控件建议使用`UniSession.AddJS`更新 2. **第三方库调用** 对于如OpenSSL等外部库(如引用[1]路径中的库),需确认其线程安全性。建议: ```delphi // 在全局单元初始化库 initialization OpenSSL_load_library; ``` 3. **批处理调用优化** 原WinExec调用方式(如引用[3])应改为: ```delphi TThread.CreateAnonymousThread( procedure begin ShellExecute(0, 'open', 'cmd.exe', '/C mybatch.bat', nil, SW_HIDE); end ).Start; ``` #### 四、性能验证方法 1. 使用`TStopwatch`记录执行时间 2. 通过浏览器开发者工具观察网络请求状态 3. 监控服务器内存使用情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值