1.對象的幾種狀態(tài)
在所有之前,說明一下,對于hibernate,它的對象有三種狀態(tài),transient、persistent、detached
下邊是常見的翻譯辦法:
transient:瞬時態(tài)或者臨時態(tài)
(new DeptPo(1,”行政部”,20,”行政相關”),該po的實例和session沒有關聯(lián),該po的實例處于transient)
persistent:持久化狀態(tài)
(和數(shù)據(jù)庫中記錄想影射的Po實例,它的狀態(tài)是persistent, 通過get和load等得到的對象都是persistent)
detached:脫管狀態(tài)或者游離態(tài)
(1)當通過get或load方法得到的po對象它們都處于persistent,但如果執(zhí)行delete(po)時(但不能執(zhí)行事務),該 po狀態(tài)就處于detached, (表示和session脫離關聯(lián)),因delete而變成游離態(tài)可以通過save或saveOrUpdate()變成持久態(tài)
(2)當把session關閉時,session緩存中的persistent的po對象也變成detached
因關閉session而變成游離態(tài)的可以通過lock、save、update變成持久態(tài)
持久態(tài)實例可以通過調(diào)用 delete()變成游離狀態(tài)。
通過get()或load()方法得到的實例都是持久化狀態(tài)的。
游離狀態(tài)的實例可以通過調(diào)用lock()或者replicate()進行持久化。
save()和persist()將會引發(fā)SQL的INSERT,delete()會引發(fā)SQLDELETE,
而update()或merge()會引發(fā)SQL UPDATE。對持久化(persistent)實例的修改在刷新提交的時候會被檢測到,它也會引起SQL UPDATE。
saveOrUpdate()或者replicate()會引發(fā)SQLINSERT或者UPDATE
可以通過session提供的方法用于改變對象的狀態(tài)。
save()方法:
1.使一個臨時對象成為持久化對象。
2.為對象分配ID。
3.在 flush緩存的時候發(fā)送一條insert語句。
4.save之前設置的ID是無效的。
5.持久化對象的ID是不可修改的。
@Test
public void testSave() {
News news = new News();
news.setAuthor("wenyu2");
news.setDate(new Date());
news.setTitle("php");
news.setId(23);//該行設置無效
System.out.println(news);
session.save(news);
System.out.println(news);
news.setId(45);//改行拋出異常。
persist()方法:
與save方法類似的是persist()方法, persist()方法也可以執(zhí)行insert操作,但是跟save的區(qū)別是,若在persist之前設置了ID值, 則拋出異常,不會insert操作。
@Test
public void testPersist() {
News news = new News();
news.setAuthor("wangwu");
news.setDate(new Date());
news.setTitle("py");
news.setId(34);//拋異常,不會執(zhí)行insert操作。
session.persist(news);
}
get()方法:該方法會立即查詢加載數(shù)據(jù)庫中的對象(立即執(zhí)行select語句)。但是若是該記錄在數(shù)據(jù)庫中不存在那么返回一個null(沒有即沒有很直接)。
@Test
public void testGet() {
News news = (News) session.get(News.class, 4);
session.close();//若是手動關閉session,下面的打印也會成功。
System.out.println(news);
}
Load()方法:該方法功能和get相同,但是屬于延遲加載的方法。
也就是說,執(zhí)行l(wèi)oad方法之后,若是不使用該對象那么不會執(zhí)行select語句,僅僅返回一個代理對象。與此同時若是查詢的記錄在數(shù)據(jù)庫中不存在,那么會拋出異常(找不到對象),可以理解為返回代理對象之后,該代理對象無法找到與之匹配的真實對象,即拋異常。
若是在使用對象之前手動關閉了session,在使用對象的時候會拋出懶加載異常。而get卻是可以打印出來。
@Test
public void testLoad() {
News news = (News) session.load(News.class, 4);
System.out.println(news.getClass().getName());
session.close();
System.out.println(news);//調(diào)用的時候拋出懶加載異常。
}
update方法:
1.若更新一個持久化對象,不需要顯示的調(diào)用update方法,因為在Transaction 的commit方法之前會先執(zhí)行flush操作(出發(fā)update語句)。
2.當session關閉或者執(zhí)行了evict方法,將對象從session 緩存中移除,那么該對象處于游離狀態(tài),此時需要顯示調(diào)用update()方法,這個update()顯示調(diào)用的時候,不論對象的屬性是否發(fā)生變化都會執(zhí)行update語句,在跟觸發(fā)器協(xié)同工作的時候,為了避免這個問題,我們可以使用在hbm.xml文件中設置select-before-date值為true,檢測是否有改變,若是沒有改變那么不會發(fā)送update語句。(該方式不常用)。
若數(shù)據(jù)表中沒有該記錄,但是還是執(zhí)行update的話,會導致異常。
當update方法關聯(lián)一個游離狀態(tài)的對象時,如果session中已經(jīng)存在相同ID的持久化對象,會拋異常,因為session 中不能存在兩個OID相同的對象。
@Test
public void testUpdate() {
News news = (News) session.get(News.class, 4);
transaction.commit();
session.close();// 至此news對象是一個游離狀態(tài)的。
// news.setId(6);//該行會拋異常,ID在數(shù)據(jù)表中不存在。
session = sessionFactory.openSession();
transaction = session.beginTransaction();
// news.setAuthor("JDBC");// news既不在原來的session緩存中,也不在新的緩存中。
// News news2=(News)session.get(News.class, 5);//
session.update(news);// 也就是需要通過顯示的執(zhí)行update方法,將該對象變?yōu)槌志脿顟B(tài)。
}
saveOrUpdate()方法:
根據(jù)是否有OID 來判斷是采用save操作還是update操作。 若OID不為空但是沒有對應的記錄,會拋異常。
@Test
public void testSaveOrUpdate() {
News news = (News) new News("FF", "ff", new Date());
news.setId(34);//若該ID在數(shù)據(jù)庫中沒有對應的記錄,拋異常。
session.saveOrUpdate(news);
}
delete方法:
可刪除一個游離對象,也可以刪除一個持久化對象。session 的delete方法處理過程:
計劃執(zhí)行一條delete語句,把對象從session緩存中刪除,該對象成為刪除狀態(tài)。
hibernate.use.identifier.rollback屬性,默認值為false,若設置為true,將改變delete行為,那么會把對象的OID置為空,成為臨時對象。
@Test
public void testDelete() {
News news = (News) session.get(News.class, 11);
session.delete(news);
// session.update(news);//刪除狀態(tài)的不可以進行update操作。
System.out.println(news);
}
Evict()方法:
@Test
public void testEvict() {
News news1 = (News) session.get(News.class, 9);
News news2 = (News) session.get(News.class, 8);
news1.setTitle("uu");
news2.setTitle("mm");
session.evict(news2);// 從緩存中移除對象,該對象成為游離狀態(tài)對象。
session.update(news2);// 該對象若是要update的話,需要顯示的調(diào)用,因為該對象已經(jīng)屬于游離對象。
}