2012-07-27 76 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/