1. 程式人生 > >通過一道面試題來引入Hibernate之懶載入

通過一道面試題來引入Hibernate之懶載入

前言

先來看看面試題:
Hibernate中get和load方法的區別?
答:相同點:都是通過主鍵查詢的方法。session.get(User.class,1);session.load(User.class,1);
不同點:
get: 及時載入,只要呼叫get方法立刻向資料庫查詢,,執行sql語句。
load:預設使用懶載入,當用到資料的時候才向資料庫查詢。 相當於做了一層優化。

懶載入:(lazy)

概念:當用到資料的時候才向資料庫查詢,這就是hibernate的懶載入特性。
目的:提供程式執行效率!

在配置檔案中設定lazy 值:
true 預設情況下使用懶載入
false 關閉懶載入

extra (在集合資料懶載入時候提升效率)
在真正使用資料的時候才向資料庫傳送查詢的sql;
如果呼叫集合的size()/isEmpty()方法,只是統計,不真正查詢資料!
集合屬性預設有懶載入!

案例分析:
本本案列均來自Hibernate系列篇中講解了部門與員工的案例,這裡直接拿程式碼來測試了。如有不明白的地方,請參考作者之前的Hibernate筆記。

先測試get方法—Lazy使用預設值true.

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction
(); Dept dept = new Dept(); // get: 及時查詢 dept = (Dept) session.get(Dept.class, 9); System.out.println(“---------------------------”); System.out.println(dept.getDeptName()); session.getTransaction().commit(); session.close(); }

列印結果:先列印sql語句,再列印“————”,最後列印部門名稱。說明get方法是直接執行資料庫查詢的(不猶豫,很果斷)。

測試load方法

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及時查詢
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,預設懶載入, 及在使用資料的時候,才向資料庫傳送查詢的sql語句!
        dept = (Dept)session.load(Dept.class, 9);
 System.out.println(“---------------------------”);
// 在這裡使用
        System.out.println(dept.getDeptName());


        session.getTransaction().commit();
        session.close();


    }

列印結果;先列印“—————–”,再列印sql查詢語句,最後再列印部門的名稱。說明load方法使用了懶載入機制,在用到dept資料的時候才向資料庫傳送查詢的sql語句!

注意:在session關閉之後,不能使用懶載入資料,也就是load查詢到的資料比如user物件,如果在session.close()之後,進行user.getName()將會報錯。

比如:程式碼如下:

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及時查詢
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,預設懶載入, 及在使用資料的時候,才向資料庫傳送查詢的sql語句!
        dept = (Dept)session.load(Dept.class, 9);
 System.out.println(“---------------------------”);

        session.getTransaction().commit();
        session.close();

// 在這裡使用
        System.out.println(dept.getDeptName());     
    }

會報錯!錯誤資訊:org.hibernate.LazyInitializationException: could not initialize proxy - no Session

還有,在使用load方法時將會返回查詢結果的代理物件。
例如:user=(User)session.load(User.class,1); 此時的user型別為User物件的代理物件。我們可以通過debug斷點除錯的方法檢視dept的型別發生了變化。

懶載入在集合中的應用:

    @Test
    public void set() {
        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = (Dept) session.get(Dept.class, 10);
        System.out.println(dept.getDeptName());
        System.out.println("------");
        System.out.println(dept.getEmps());  //  SQL

        session.getTransaction().commit();
        session.close();

    }

列印順序:先查詢部門的sql語句,然後列印部門的名稱,再列印“———–”,然後查詢員工的sql語句,最後列印該部門下的全部的員工。這就是懶載入在集合中的應用,即如果在具體的實際開發中,我們只想要部門的名稱等資訊,不會去關心該部門下的具體員工,那麼將lazy=true,會提高Hibernate對資料庫操作的效率。

但是有些時候,我們又想查詢部門的時候,也同時查出來員工的資訊,那麼就必須把lazy改為flase.因為有時在實際的專案中查詢跟資料庫操作有關,一般會放在service層中,如果在頁面載入之前呼叫一次service層中的方法,就想查詢部門和員工的資訊,並且在頁面中顯示,那麼怎麼辦呢?這就考慮關閉懶載入了。之後的專案開發案例中會給出具體的應用。

那麼還有一點,如何解決session關閉後不能使用懶載入資料的問題?
// 方式1: 在session關閉之前先使用一下資料
//dept.getDeptName();

// 方式2:session關閉之前強迫代理物件初始化
Hibernate.initialize(dept);

// 方式3:關閉懶載入
設定lazy=false;

// 方式4: 在使用資料之後,再關閉session!

測試程式碼如下:

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及時查詢
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,預設懶載入, 及在使用資料的時候,才向資料庫傳送查詢的sql語句!
        dept = (Dept)session.load(Dept.class, 9);
        // 方式1: 先使用一下資料
        //dept.getDeptName();
        // 方式2:強迫代理物件初始化
        Hibernate.initialize(dept);
        // 方式3:關閉懶載入

        session.getTransaction().commit();
        session.close();

        // 在這裡使用
        System.out.println(dept.getDeptName());
    }

最後,說一下集合中lazy=extra 的用法。
如果呼叫集合的size()/isEmpty()方法,只是統計,不真正查詢資料!

測試:

@Test
    public void set() {
        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = (Dept) session.get(Dept.class, 10);
        System.out.println(dept.getDeptName());
        System.out.println("------");
        System.out.println(dept.getEmps().isEmpty());  //  SQL

        session.getTransaction().commit();
        session.close();

    }

輸出順序:部門名稱,“—-”然後是“select count(id) form t_employee‘’的sql語句,說明size或者isEmpty方法只會查詢員工表的總記錄數,不會查詢員工的全部資訊。這也算是一種優化策略!