1. 程式人生 > >【SSH快速進階】——探索Hibernate物件的三種狀態:Transient、Persistent、Detached

【SSH快速進階】——探索Hibernate物件的三種狀態:Transient、Persistent、Detached



  學習過作業系統的朋友,腦子裡肯定都會有這張程序的狀態轉換圖:

  這裡寫圖片描述

  當所有條件就緒,程序被排程執行,時間片到的時候,程序被掛起,進入就緒狀態……對程序進行的不同操作會導致程序進入到不同的狀態。

  Hibernate中物件的有三種狀態:臨時狀態(Transient)、持久化狀態(Persistent)、遊離狀態(Detached),這三種狀態也隨著對其執行不同的操作互相轉換。

  先看一張圖來巨集觀瞭解一下這三種狀態:

  這裡寫圖片描述

  下面分別對這三種狀態進行說明(為了簡潔直觀,本文所有程式碼均沒有加異常處理)

1、臨時狀態(Transient):

  簡單來說,處於Transient的物件,就是我們剛new出來、尚未被session管理

的物件。它與資料庫沒有任何交集(資料庫中沒有與之對應的資料),可以被看做是攜帶資訊的載體,可以對物件本身的屬性、方法進行操作。

  比如:

    User user=new User();
    user.setName="Danny";
    user.setPassword="123456";

  這時的user就是處於Transient狀態的物件。

2、 持久化狀態(Persistent):

  Persistent的物件,已經被加入到session快取中(被session管理)。對持久化狀態的物件進行的操作,只是暫時在快取內部的變化,在commit之前,並沒有提交到資料庫,但在資料庫中存在與之對應的資料

(這句話可能會有些朋友會不太明白,下面會稍作解釋)。

    //讀取配置檔案
    Configuration cfg=new Configuration().configure();
    //建立SessionFactory
    factory=cfg.buildSessionFactory();
    //獲取session
    Session session = factory.openSession();
    //事務開啟
    Transaction tx = session.beginTransaction();

    //Transient狀態
    User user = new User();
user.setName("Danny"); user.setPassword("123456"); // Persistent狀態 session.save(user); user.setName("DannyHoo"); tx.commit(); session.close;

  如上,當session對user執行了save/saveOrUpdate方法後,user物件狀態由Transient轉化為Persistent,這時我們對其操作,都會記錄在session的快取中。

  比如上面的例子,先對user執行了setName(“Danny”)的操作,然後進行save操作,在事務提交之前,又對user執行了setName(“DannyHoo”)的操作。對user執行的save操作就相當於向資料庫執行了插入操作,隨後對user執行的setName(“DannyHoo”)相當於執行了一次更新操作,當事務提交,對快取進行清理(髒資料檢查)的時候,會和資料庫同步,執行兩條sql語句。

    Hibernate: insert into User (name, password, id) values (?, ?, ?)
    Hibernate: update User set name=?, password=? where id=?

  在session.save()之後和session.close之前,user一直處於Persistent狀態。

  然後再通過上面的例子解釋一下“在資料庫中存在與之對應的資料”這句話,在例子中,User類的主鍵生成策略為uuid,我並沒有在程式碼中為user設定id,在save(user)之前,user的id為null,save之後,user的id已經生成:
save之前:

這裡寫圖片描述

  save之後:

這裡寫圖片描述

  這時,在session的快取中已經有一份與資料庫中相對應的一條資料了(可以說user已經在真正意義上成為資料庫中的一條記錄了),只不過沒提交事務之前還沒更新到資料庫中,一旦提交事務,便會將這條記錄“copy”到資料庫中。

3、遊離狀態(Detached):

  遊離狀態的物件,不受session管理,而且在資料庫中存在與之對應的資料。根據上文可知當session執行close(關閉)、clear(清除快取)之後,被session管理的物件的狀態就由Persistent轉化為Detached;當session執行了evict (逐出)之後,被逐出的物件的狀態就由Persistent轉化為Detached。

    //讀取配置檔案
    Configuration cfg=new Configuration().configure();
    //建立SessionFactory
    factory=cfg.buildSessionFactory();
    //獲取session
    Session session = factory.openSession();
    //開啟事務
    Transaction tx = session.beginTransaction();

    //Transient狀態
    User user = new User();
    user.setName("Danny");
    user.setPassword("123456");

    // Persistent狀態
    session.save(user);
    user.setName("DannyHoo");

    //提交事務,session關閉
    tx.commit();
    session.close;

    //Detached狀態
    user.setName("胡玉洋");

    //重新開啟session
    Session session = factory.openSession();

    //重新開啟事務
    tx = session.beginTransaction();
    //再次將user納入session管理,save之後user又將程式設計Persistent狀態,最後在session檢查髒資料時會將資料庫同步到與session快取中的資料一致
    session.update(user);

    //提交事務,session關閉
    tx.commit();
    session.close;

  上述程式碼中,在session第一次關閉之後,user的狀態就由Persistent轉化為Detached,它跟資料庫中的資料一致,可以看做是已經真正更新到資料庫中的狀態。

Hibernate中常用方法

  最後簡單介紹一下session中的幾個常用方法,來幫助理解Hibernate物件的這三種狀態。
  
   ● get():根據id查詢記錄,如果查詢結果為空,返回null;
   ● load():根據id查詢記錄,如果查詢結果為空,丟擲ObjectNotFoundException,並且load支援懶載入,通過get和load查詢出的記錄會立刻進入Persistent狀態;
   ● save:save方法將物件儲存到資料庫,但並沒有立即執行插入語句,只是將物件加入到session快取中,根據主鍵生成策略生成主鍵(即時物件中已經有id也會重新生成一份),生成insert語句;
   ● saveOrUpdate:判斷資料庫中是否存在與之對應的資料,如果存在,只更新,否則插入,通過save和saveOrUpdate方法,物件會立即進入Persistent狀態;
   ● evict:evict方法將指定物件從session快取中逐出,使其進入Detached狀態;
   ● close:close關閉session;
   ● clear:清除session中所有快取;
   ● update:當對一個Detached狀態的物件更新(update)的時候,會使其進入持久化狀態。
   ● delete:當對一個Persistent或Detached狀態的物件刪除的時候,會使其進入Transient狀態。