1. 程式人生 > >SSS框架整合no session(延遲載入)問題分析及解決

SSS框架整合no session(延遲載入)問題分析及解決

問題描述:

        在做BOS物流管理系統的時候,點選區域頁面顯示配送區域資訊,這個時候後臺顯示了no session的錯誤

org.apache.struts2.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.itheima.domain.Area.subareas, could not initialize proxy - no Session
	at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:246)
	at org.apache.struts2.json.JSONWriter.processCustom(JSONWriter.java:178)
	at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:168)
	at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:134)
	at org.apache.struts2.json.JSONWriter.array(JSONWriter.java:492)
	at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:158)
	at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:134)
	at org.apache.struts2.json.JSONWriter.map(JSONWriter.java:447)
	at org.apache.struts2.json.JSONWriter.process(JSONWriter.java:154)
	at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:134)
	at org.apache.struts2.json.JSONWriter.write(JSONWriter.java:102)
	at org.apache.struts2.json.JSONUtil.serialize(JSONUtil.java:107)
	at org.apache.struts2.json.JSONResult.createJSONString(JSONResult.java:203)
	at org.apache.struts2.json.JSONResult.execute(JSONResult.java:177)
	at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:369)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:273)
	at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.itheima.domain.Area.subareas, could not initialize proxy - no Session
	at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:563)
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:205)
	at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:542)
	at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:133)
	at org.hibernate.collection.internal.PersistentSet.equals(PersistentSet.java:423)
	at java.util.Vector.indexOf(Vector.java:411)
	at java.util.Vector.contains(Vector.java:370)
	at org.apache.struts2.json.JSONWriter.value(JSONWriter.java:117)
	at org.apache.struts2.json.JSONWriter.add(JSONWriter.java:401)
	at org.apache.struts2.json.JSONWriter.bean(JSONWriter.java:231)
	... 81 more

看系統提示可以看出來是因為載入Area類中的subareas屬性出現了問題。我們再來看下Area類中有哪些屬性

        @Id
	@Column(name = "C_ID")
	private String id;
	@Column(name = "C_PROVINCE")
	private String province; // 省
	@Column(name = "C_CITY")
	private String city; // 城市
	@Column(name = "C_DISTRICT")
	private String district; // 區域
	@Column(name = "C_POSTCODE")
	private String postcode; // 郵編
	@Column(name = "C_CITYCODE")
	private String citycode; // 城市編碼
	@Column(name = "C_SHORTCODE")
	private String shortcode; // 簡碼

	@OneToMany(mappedBy = "area")
	private Set<SubArea> subareas = new HashSet<SubArea>();

        為什麼Area中這麼多屬性,只有subareas屬性出現了問題?可以看出來這裡的subareas是一個集合,問題就出現在這裡,在spring框架中集合屬性的查詢預設的是懶載入的,也就是說在service層呼叫dao層的查詢方法時,dao層並不會向資料庫傳送查詢語句,而是將查詢語句藏在了session的一級快取區域,在下一次subareas被使用到的時候才會真正向資料區傳送查詢語句,這樣的好處是可以為系統節省資源,但是同樣也帶來一個問題,因為我們第一次呼叫subareas是在web層將查詢到的資料打包成json資料的時候,但是我們的session在service層就已經被關閉了,我們都知道sss框架和ssh框架的底層都是Hibernate中的session物件對資料庫進行操作的。因此就會出現no session的異常。

問題解決:

第一種:讓session存活到web層

    新增OpenEntityManagerInViewFilter過濾器(必須配置在struts攔截器前),原理就是將session的建立和關閉放在過濾器中,這樣就可以讓session存活到web層。

第二種:立即載入(不建議)

        立即載入就是消除懶載入,運用JPA註解的屬性fetch=FetchType.EAGER

        @OneToMany(mappedBy = "area",fetch=FetchType.EAGER)
	private Set<SubArea> subareas = new HashSet<SubArea>();

      這樣就可以在dao層立即載入subareas,這樣在web層就可以直接使用到subareas的資料了。

第三種:取消序列化

        如果subareas這個屬性並不是需要的資料的話,可以通過註解讓json在序列化Area的屬性的時候,跳過subareas這個屬性。這樣就不需要向資料庫查詢subareas的資料了,也就不會出現懶載入的問題了。