1. 程式人生 > ># 新人淺談對hibernate的懶載入的理解

# 新人淺談對hibernate的懶載入的理解

新人淺談對hibernate的懶載入的理解

懶載入是hibernate中常見的特性之一。
懶載入的好處:
可以減少程式本身因為與資料庫頻繁互動資料所導致的處理速度緩慢。
對懶載入異常的分析:
實驗程式碼如下:
Department類:

public class Department {
    private Long id;
    private Department parent;//關聯上級部門
    private Set<Department> children = new HashSet<Department>();//關聯下級部門

    private
String name; private String description; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Department getParent() { return parent; } public void setParent(Department parent) { this.parent = parent; } public
Set<Department> getChildren() { return children; } public void setChildren(Set<Department> children) { this.children = children; } public String getName() { return name; } public void setName(String name) { this.name = name; } public
String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }

Department.hbm.xml:

<!-- parent屬性,本類與Department(上級)的多對一 -->
        <many-to-one name="parent" class="Department" column="parentId"></many-to-one>


        <!-- children屬性,本類與Department(下級)的一對多 -->
        <set name="children" cascade="delete" order-by="id ASC">
            <key column="parentId"></key>
            <one-to-many class="Department" />
        </set>

DAO層程式碼:

public List<Department> findTopList() {
        return sessionFactory.getCurrentSession().createQuery(
                "FROM Department d WHERE d.parent IS NULL")
                .list();
    }

    public List<Department> findChildren(Long parentId) {
        return sessionFactory.getCurrentSession().createQuery(
                "FROM Department d WHERE d.parent.id=?")
                .setParameter(0, parentId)
                .list();
    }

Action:

public String list() throws Exception {
        List<Department> departmentList = null;
        if (parentId == null) { // 頂級部門列表
            departmentList = departmentService.findTopList();
        } else { // 子部門列表
            departmentList = departmentService.findChildren(parentId);
            Department parent = departmentService.getById(parentId);
            ActionContext.getContext().put("parent", parent);
        }
        ActionContext.getContext().put("departmentList", departmentList);
        return "list";
    }

執行該段程式碼,在第一次查詢頂級部門時,是可以執行的,但是第二次查詢子部門時,會出現懶載入異常

原因分析:
執行findTopList()findChildren方法時,預設使用懶載入,*即載入關聯實體類時,並不是直接載入指定物件,而是載入一個代理物件,當你想使用關聯實體類時在從資料庫中查詢。
*在檢視層需要顯示上級部門這個屬性,這意味著要在檢視層載入Department類 的parent 屬性的name屬性。
findTopList() 這個方法所查詢的Department類 的parent是為null,故而不出現懶載入異常。
findChildren方法所查詢出的parent不為null,當檢視層載入parent的name屬性是session已經被關閉了,此時懶載入之前載入的代理物件失效,無法從資料庫中查詢出parent的值,導致了懶載入異常的發生。
故而懶載入異常發生的主要原因是:實體類物件還未載入完成,負責載入實體類物件的session就已經關閉了。
解決方案:
①,設定lazy=”false”。該方法存在缺點,即減低了效率。我們將所有相關聯的資料都查詢了,頻繁的查詢降低了效率。不建議採用!
②,使用Spring的過濾器:OpenSessionInViewFilter;它把session繫結到請求執行緒中,session將自動的被Spring的事務管理器管理。即service層完成了事務,session也會繼續開啟,支援延遲載入的操作,知道檢視層完全載入完畢。
具體配置:

<!-- 配置Spring的用於解決懶載入問題的過濾器 -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <url-pattern>*.action</url-pattern>
    </filter-mapping>

PS:為了方便攔截器的使用,減低沒必要使用,建議將Struts2的字尾統一,如*.action。
新人寫博文,請多指教。