Hibernate 常用的數(shù)據(jù)庫操作方法
1. 前言
本節(jié)課程聊聊如何使用 Session 完成基本數(shù)據(jù)操作。通過本課程,你將學(xué)習(xí)到:
- 如何實現(xiàn)查詢;
- 如何實現(xiàn)保存和更新。
2. 基本數(shù)據(jù)操作方法
Session 中提供了很多方法,協(xié)助開發(fā)者快速完成基本的增加、刪除、修改、查詢(CRUD) 等基本數(shù)據(jù)操作。
2.1 查詢
Session 提供了 2 個語義很明確的查詢方法:
- get() 方法;
- load() 方法。
有選擇,就會有比較。但,請先不用著急區(qū)分兩者差異性,試著用用。
跑之前先學(xué)會走嗎?
查詢之前,可預(yù)先在表中多添加幾條數(shù)據(jù)!避免池塘沒魚,捕不到魚還不停懷疑自己,傷情緒。
get() 方法有很多重載,選擇其中一個方法:
public Object get(Class clazz, Serializable id);
- 參數(shù)一: 指定待查詢的 PO 對象的類型;
- 參數(shù)二: 指定一個實現(xiàn) Serializable 接口的對象,充當(dāng)查詢條件,一般是主鍵。
編寫 get() 方法的查詢測試實例:
@Test
public void testGet() {
//會話對象
Session session = sessionFactory.openSession();
// 事務(wù)對象
Transaction transaction = null;
try {
// 打開事務(wù)
transaction = session.beginTransaction();
//查詢學(xué)號為1的學(xué)生
Student stu=(Student)session.get(Student.class, new Integer(1));
assertEquals("男", stu.getStuSex());
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
編寫 load() 方法的查詢測試實例:
@Test
public void testLoad() {
//會話對象
Session session = sessionFactory.openSession();
// 事務(wù)對象
Transaction transaction = null;
try {
// 打開事務(wù)
transaction = session.beginTransaction();
//查詢學(xué)號為1的學(xué)生
Student stu=(Student)session.load(Student.class, new Integer(2));
assertEquals("男", stu.getStuSex());
transaction.commit();
} catch(Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
測試代碼和上面沒有很明顯區(qū)別,結(jié)果也沒有什么不同。
這兩個方法從測試角度暫時無法區(qū)分,但本質(zhì)上還是有很大區(qū)別。
2.2 更新、刪除
添加數(shù)據(jù)的代碼前面課程中已經(jīng)使用多次,現(xiàn)在討論更新、刪除。更新、刪除的前提條件:
- 更新、刪除數(shù)據(jù)一定是數(shù)據(jù)庫中的數(shù)據(jù);
- 更新、刪除包括一個前置操作,查詢操作。
Session 提供了 public void delete(Object obj) 方法用來刪除數(shù)據(jù)。
編寫刪除測試實例,先查詢,再刪除:
@Test
public void testDelete() {
Session session = sessionFactory.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
//查詢學(xué)號為1的學(xué)生
Student stu=(Student)session.load(Student.class, new Integer(1));
System.out.println(stu);
session.delete(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
運行后,結(jié)果很明顯,數(shù)據(jù)庫中數(shù)據(jù)被刪除。
事務(wù)問題:
事務(wù)是一個較復(fù)雜的主題(后有專題課程),原生 JDBC 中,事務(wù)管理方式有:
- 數(shù)據(jù)庫管理;
- JDBC API 管理。
Hibernate 提供了 Transaction 對象,用來對事務(wù)進(jìn)行管理。
默認(rèn):autoCommit=false,意思是底層 JDBC 把事務(wù)交給 Hibernate 管理。
查詢時,可以忽略事務(wù)。使用 Hibernate 進(jìn)行增、刪、改時。須顯示調(diào)用 Transaction 的 commit() 或 rollback() 方法。
Session 提供了 public void update(Object object) 方法用于數(shù)據(jù)更新。
編寫更新的測試代碼:
@Test
public void testUpdate() {
//會話對象
Session session = sessionFactory.openSession();
// 事務(wù)對象
Transaction transaction = null;
try {
// 打開事務(wù)
transaction = session.beginTransaction();
//查詢學(xué)號為1的學(xué)生
Student stu=(Student)session.load(Student.class, new Integer(1));
stu.setStuName("session同學(xué)");
session.update(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
結(jié)果沒有什么意外,在程序中修改的數(shù)據(jù)通過 update() 方法同步到數(shù)據(jù)庫。
如果查詢 API 文檔,會發(fā)現(xiàn)除了這些語義上很明確的方法外,還有其它幾個方法
- public void saveOrUpdate(Object object);
- public Object merge(Object object);
- public void persist(Object object);
可以使用測試方式得到基本結(jié)論,如編寫一個添加數(shù)據(jù)的實例時,使用 save、saveOrUpdate、persist 都可達(dá)到相同結(jié)果。
@Test
public void testAdd() {
Session session = sessionFactory.openSession();
// 事務(wù)對象
Transaction transaction = null;
try {
// 打開事務(wù)
transaction = session.beginTransaction();
//添加新學(xué)生
Student stu=new Student("慕課網(wǎng)", "男");
//可換成saveOrUpdate方法,save方法
session.persist(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
本節(jié)課,只從語義層面做區(qū)分,其內(nèi)在差異性留到后續(xù)課程中慢慢揭曉,算是留下一個懸念。
休息一下,小結(jié)一下:
- Get()、Load()方法可用于查詢;
- Save()可用于添加;
- Update()可用于更新數(shù)據(jù);
- Delete()可用于刪除;
- saveOrUpdate()有兩重性,沒有數(shù)據(jù)時添加數(shù)據(jù),有數(shù)據(jù)時更新數(shù)據(jù);
- persist()方法可用于更新、添加數(shù)據(jù);
- merge()方法可用于更新、添加數(shù)據(jù)。
是不是有點上頭了,心累呀!Hibernate 不地道呀,搞出這么多方法,這是要逼得有選擇困難癥的人哭,其實每一個方法都有特定的應(yīng)用場景,Hibernate 總是體貼入微的想著為開發(fā)者解決每一種開發(fā)場景的需求。
記住剛開始說的,抓住主分支(知道層面),不管細(xì)節(jié)(內(nèi)部機制層面)。
2.3 保存大對象
能不能把一張圖片保存到數(shù)據(jù)庫?
答案是明確的。
真實應(yīng)用場景中不會這么做。
數(shù)據(jù)庫中只會保存圖片路徑,具體的圖片文件會存儲在文件服務(wù)器中。
Hibernate 支持的大對象有:
- Clob:文本大對象;
- Blob:二進(jìn)制數(shù)據(jù)大對象。
現(xiàn)在為每一個學(xué)生保存?zhèn)€人圖片:
- student 類中添加 stuPic 屬性(注意類型):
private Blob stuPic;
- 編寫測試實例:
@Test
public void testInsertPic() {
//會話對象
Session session = sessionFactory.openSession();
// 事務(wù)對象
Transaction transaction = null;
try {
// 打開事務(wù)
transaction = session.beginTransaction();
//添加新學(xué)生
Student stu=new Student("MK", "男");
InputStream is=new FileInputStream("pic.png");
Blob stuPic=Hibernate.getLobCreator(session).createBlob(is, is.available());
stu.setStuPic(stuPic);
session.merge(stu);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
session.close();
}
}
如果要保存文本大對象,則使用如下代碼:
Clob c=Hibernate.getLobCreator(session).createClob("我是中國人……");
執(zhí)行結(jié)果,不出意外,數(shù)據(jù)保存成功。
不要試著把很多圖片直接保存到數(shù)據(jù)庫中,圖片的存儲與查詢會比較慢,會嚴(yán)重拖累數(shù)據(jù)庫性能。另外數(shù)據(jù)庫的體積也會變得臃腫不堪,現(xiàn)在可是一個以瘦為美的世界!
如何讀取數(shù)據(jù)庫中保存的圖片?
相信你一定能找到答案。
3. 總結(jié)
本節(jié)課程以體驗式的方式感受了 Session 為開發(fā)者提供的常用方法。
對于類似的操作,Hibernate 會有備選方法選擇,其內(nèi)在的具體細(xì)節(jié)將在后續(xù)課程一一揭曉。
不要質(zhì)疑 Hibernate 為什么要提供看似雷同的方法,真實場景中的需求要比 Hibernate 所能想到的更復(fù)雜。Hibenate 只是想以周全的態(tài)度為開發(fā)者保駕護(hù)航。
Hibernate 對開發(fā)者愛得深,細(xì)言碎語也就多??!