2012-07-27 78 views
3

我有一个Spring,Hibernate和Wicket应用程序设置为从数据库中读取国际化的json内容项并通过api url上的请求传递出去。负责传递数据的代码库是为企业客户开发的整体网站结构的一小部分。Hibernate OpenSessionInViewFilter过早关闭会话?

在超过90%的情况下,api的功能很好,但客户正在经历一个有趣的偶发性问题,这可能是由于孤立的hibernate会话导致的。该请求将通过PHP脚本失败,并给出错误:

Warning: file_get_contents(http://client.net/api/attachment_lines?ce=false&language=en&region=na&ts=1341592326) [function.file-get-contents]: failed to open stream: Redirection limit reached, aborting in client_api->send_request() (line 38 of <sitepath>/api.class.php). 

而且将产生下面的错误在Tomcat服务器日志:

09:15:00,200 ERROR [RequestCycle] failed to lazily initialize a collection of role: com.client.data.AttachmentLineCode.attachmentSublineCodes, no session or session was closed 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.client.data.AttachmentLineCode.attachmentSublineCodes, no session or session was closed 

应用程序被弹簧内配置为使用的OpenSessionInViewFilter和@Transactional注释设计模式,所以我不确定是什么导致间歇性请求失败。除此之外,客户指出,在问题发生后约15分钟,api将继续失败,这在配置上看起来确实很古怪。在web.xml中,这里是过滤器的声明:

<filter> 
    <filter-name>openEntityManagerInView</filter-name> 
    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>openEntityManagerInView</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

内的代码,这里是通用的DAO事务注释这是由内容项DAO扩展:

@Transactional(noRollbackFor={javax.persistence.EntityNotFoundException.class, org.springframework.orm.ObjectRetrievalFailureException.class}) 
public class GenericDaoHibernate<T, PK extends Serializable> implements GenericDao<T, PK> { 
    @Autowired 
    private SessionFactory sessionFactory; 

内泛型DAO为好,这里是我检索和使用会话:

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

protected Criteria createCacheableCriteria(Class<T> clazz) { 
    Criteria criteria = createNonCacheableCriteria(clazz); 
    criteria.setCacheable(true); 
    criteria.setCacheMode(CacheMode.NORMAL); 
    return criteria; 
} 

protected Criteria createCacheableCriteria(Class<?> clazz, String alias) { 
    Criteria criteria = createNonCacheableCriteria(clazz, alias); 
    criteria.setCacheable(true); 
    criteria.setCacheMode(CacheMode.NORMAL); 
    return criteria; 
} 

protected Criteria createNonCacheableCriteria(Class<?> clazz) { 
    Session session = getSession(); 
    Criteria criteria = session.createCriteria(clazz); 
    criteria.setCacheable(false); 
    criteria.setCacheMode(CacheMode.IGNORE); 
    return criteria; 
} 

protected Criteria createNonCacheableCriteria(Class<?> clazz, String alias) { 
    Session session = getSession(); 
    Criteria criteria = session.createCriteria(clazz, alias); 
    criteria.setCacheable(false); 
    criteria.setCacheMode(CacheMode.IGNORE); 
    return criteria; 
} 

是否有某种方式,本次会议可以在这个设置得到孤儿?是否有某种内置的超时时间来休眠会导致此问题的会话?缓存可能存在问题?在此先感谢您的帮助。

+0

你是如何使用'SessionFactory'?通过'HibernateTemplate'?你能给我们一个草案的代码吗? – 2012-07-27 20:04:21

+0

添加了与我使用SessionFactory相关的其他代码。谢谢回复! – Wertible 2012-07-30 16:07:25

回答

1

这里的解决方案与Hibernate或Spring没有任何关系,只存在于我的错误中,没有注意到生产环境和我们的开发/分期之间的差异。生产环境实施了复杂的负载平衡策略,没有粘性会话。

事实证明,Wicket的请求/响应周期涉及在POST后缓存缓冲响应。相应的GET回来拾取该响应会偶尔抛出302,因为负载平衡会将请求转发给服务器而没有缓存响应,并且代理对象会遗忘。我选择的代码中的相关部分落实解决,这是根据初始化放在我Application.java内():

public class ClientApplication extends SpringWebApplication { 
    ... 
    public void init() { 
     ... 
     getRequestCycleSettings().setRenderStrategy(IRequestCycleSettings.ONE_PASS_RENDER); 

这改变Wicket的渲染策略配置不缓存响应。结果出现了一个问题,允许经典的“刷新双提交”问题。因此,这不一定是理想的解决方案,但客户端不想使用启用粘滞会话的负载平衡,并且不介意有双重提交问题。

关于这个问题,一个更为雄辩/结构的答案的详细信息,请参阅:http://blog.comsysto.com/2011/04/08/lost-in-redirection-with-apache-wicket/