【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狀態。