程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> spring在MVC層解決JPA的緩遲加載問題

spring在MVC層解決JPA的緩遲加載問題

編輯:關於JAVA

作為EJB3.0的一部分,JPA是一個好東西。其簡單的配置方式及強大的默認配置支持,使其可以輕松自由的存在於輕量與重量之間,如果現在您的JavaEE項目,不管是選擇輕量級構架還是重量級構架,如果持久層不選擇使用JPA,而是用一些ORM框架(如Hibernate、TopLink)的專用API,那麼在將來的某一天一定會為這個選擇而說出至尊寶那句“假如上天再給我一個機會…”的至理名言。

下面是一個簡單的Entity,是對一個CMS系統中,關於樹狀信息目錄實體類的定義,包括了一些詳細的映射的配置信息。

@Entity

public class NewsDir ...{

@Id

@GeneratedValue(strategy = GenerationType.TABLE)

private Long id;// 主鍵

@Column(unique = true, nullable = false, length = 16)

private String sn;// 目錄編號

private String title; // 目錄名稱

@OneToMany(mappedBy = "parent", cascade = Javax.persistence.CascadeType.REMOVE)

private List children = new Java.util.ArrayList();// 下級目錄

@ManyToOne

private NewsDir parent;// 父級目錄

}

當然,跟任何其它優秀的技術一樣,JPA也不是完美的,在使用的過程中難免都會出這樣那樣的問題,這就需要我們程序員具有格物致知的本領,在應用中靈活應付這些問題。

這裡例舉一個緩遲加載的問題,以上面的新聞目錄Entity為例。對於parnet與children這個一對多的雙向關聯,為了提高系統效率,children默認使用的是緩遲加載的方式。在一些輕量級的構架中,由於脫離了J2EE容器及事務支持,經常會出現Entity脫離了Persitence Context,變成了detach或EntityManager關閉,導致一些我們預想中的一些功能無法正常運行。

最常見的就是在使用MVC框架的時候,在表示層無法加載需要緩遲加載的數據。比如,在一個基於EasyJWeb的mvc應用中,action中的方法如下:

public Page doList(WebForm form, Module module) ...{

NewsDirQueryObject ndqo = new NewsDirQueryObject();

form.toPo(ndqo);

ndqo.setDel(true);

IPageList pageList = service.queryDirsByConditions(ndqo);

CommUtilForTeaec.saveIPageList2WebForm(pageList, form);

form.addResult("dirPath", this.getDirPath(form));

return module.findPage("list");

}

在模板文件中有如下內容:

#foreach($info in ${dir.children})

目錄名稱:${info.title}

#end

關於業務邏輯層Bean的配置:

expression="execution(* com.easyjf.cms.service.*.*(..))" />

pointcut-ref="CmsManage" />

transaction-manager="transactionManager">

read-only="true" />

read-only="true" />

class="com.easyjf.cms.service.impl.CmsManageServiceImpl">

在這裡,當mvc層執行到$!info.getChildren()方法的時候,將會用到緩遲加載,由於Spring的事務是配置在service層的,因此在執行service.queryDirsByConditions方法完成後就關閉了事務。因此運行程序就會出現類似下面的錯誤信息:

2007-03-28 00:39:35,750 ERROR [org.hibernate.LazyInitializationException] - failed to lazily initialize a collection of role: com.easyjf.cms.domain.NewsDir.children, no session or session was closed

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.easyjf.cms.domain.NewsDir.children, no session or session was closed

at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.Java:358)

at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.Java:350)

at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.Java:97)

使用其它的mvc如struts、webwork乃至spring mvc都會有這樣的問題,問題的核心是在事務啟動及結束上,由於我們都習慣於在service層而非mvc配置及使用事務,導致了這樣的問題。解決的辦法其實很簡單,就是把事務的啟動放到mvc層,

讓mvc層的controller來開啟事務,而讓業務層的方法加入的事務中。比如,在EasyJWeb中,可以通過如下的配置來實現實現在action中開啟事務:

在Spring配置文件中配置EasyJWeb的核心處理器,並把process方法添加到事務中,配置文件如下:

expression="execution(* com.easyjf.web.RequestProcessor.process(..))" />

pointcut-ref="easyjwebProcessor" />

transaction-manager="transactionManager">

只需要這樣簡單的配置,你會驚奇的發現,所有緩遲加載及其它由Persitence Context無效而引起的問題均解決了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved