Hibernate_緩存&事務(wù)&批量查詢概述
一、 Hibernate的持久化類
持久化類是指一個(gè)Java類和數(shù)據(jù)庫建立了映射關(guān)系掰吕,那么這個(gè)類就是持久化類。
1. 持久化類的編寫規(guī)則:
- 持久化類需要有無參的構(gòu)造方法颅痊。
- 因?yàn)镠ibernate的底層需要使用反射生成類的實(shí)例殖熟。
- 持久化類的屬性需要私有,私有的屬性需要提供set和get方法。
- 因?yàn)镠ibernate底層要將查詢到的數(shù)據(jù)進(jìn)行封裝斑响。
- 持久化類盡量使用包裝類的類型菱属。
- 因?yàn)榘b類與普通類的默認(rèn)值不同钳榨。例:Integer為null,int為0.在數(shù)據(jù)庫表中代表的含義包裝類更準(zhǔn)確。
- 持久化類需要有一個(gè)唯一標(biāo)識(shí)OID與表的主鍵對應(yīng)纽门。
- Hibernate不允許在內(nèi)存中出現(xiàn)兩個(gè)相同OID的持久化對象薛耻。
- 持久化類不能使用final修飾。
- 因?yàn)镠ibernate中有延遲加載機(jī)制,這個(gè)機(jī)制會(huì)產(chǎn)生代理對象膜毁。而這個(gè)代理對象是使用字節(jié)碼的增強(qiáng)技術(shù)完成的昭卓,其實(shí)就是產(chǎn)生了一個(gè)當(dāng)前類的子類對象實(shí)現(xiàn)的。
2. Hibernate的主鍵生成策略
- 自然主鍵
- 把具有業(yè)務(wù)含義的字段作為主鍵瘟滨。
- 代理主鍵
- 把不具備業(yè)務(wù)含義的字段作為主鍵,與對象本身無關(guān),該字段一般取名"ID".
我們在映射文件中設(shè)置選擇native,根據(jù)數(shù)據(jù)庫底層的支持來自動(dòng)生成策略能颁。
3. 持久化對象的三種狀態(tài)
- 瞬時(shí)態(tài)
- 沒有OID杂瘸,與Hibernate的Session沒有任何關(guān)聯(lián)
- 持久態(tài)
- 有OID,與Session有關(guān)聯(lián)
- 托管態(tài)
- 有OID伙菊,與Session沒有關(guān)聯(lián)
瞬時(shí)態(tài):
對象創(chuàng)建時(shí),就是瞬時(shí)態(tài)败玉。
如: User user = new User();
user.serUname("悟空");
user.setUpassword("123");
這里面的user都是瞬時(shí)態(tài),沒有OID,與Session沒有關(guān)聯(lián)镜硕。
持久態(tài):
session.save(user);
這里的user與session產(chǎn)生關(guān)聯(lián)运翼,加入到了Session的緩存中,生成了持久化標(biāo)識(shí)OID,是持久態(tài)
此外,get/load/find...等方法獲取的對象也是持久態(tài)對象
托管態(tài):
session.close();
System.out.println(user);
這里的user有了OID,但是與Session沒有了關(guān)聯(lián),是托管態(tài)
持久化對象的三種對象之間的互相轉(zhuǎn)換:
上圖:
1. 一個(gè)對象被new出來之后處于瞬時(shí)態(tài)兴枯;當(dāng)對瞬時(shí)態(tài)對象執(zhí)行Session對象的save()/saveOrUpdate()方法后血淌,
該對象會(huì)被放入Session的一級(jí)緩存,進(jìn)入持久態(tài);當(dāng)對持久態(tài)對象執(zhí)行evict()/close()/clear()操作后,
對象進(jìn)入托管態(tài)财剖。
2. Session對象直接執(zhí)行g(shù)et()/load()/find()/iterate()等方法從數(shù)據(jù)庫查詢對象時(shí),查詢到的對象也屬于
持久態(tài)悠夯;
3. 當(dāng)對托管態(tài)對象執(zhí)行Session的upadte()/saveOrUpadate()方法時(shí),會(huì)轉(zhuǎn)為持久態(tài);瞬時(shí)態(tài)與托管態(tài)的對象
不在Session對象的管理范圍內(nèi)躺坟,因此一段時(shí)間后會(huì)被JVM回收沦补。
持久化對象的特點(diǎn):能夠自動(dòng)更新數(shù)據(jù)庫
持久化對象能夠自動(dòng)更新數(shù)據(jù)庫依賴于Hibernate的一級(jí)緩存。
@Test
//Hibernate持久化對象自動(dòng)更新數(shù)據(jù)庫
public void test() {
//1. 獲取Hibernate配置對象加載配置
//2. 獲取SessionFactory對象
//3. 獲取Session對象
Session session = HibernateUtils.openSession();
//4. 開啟事務(wù)
Transaction transaction = session.beginTransaction();
//5. 執(zhí)行業(yè)務(wù)邏輯
User user = session.get(User.class, 2);//獲得持久化對象
user.setUname("外星人");
//無需手動(dòng)調(diào)用session.save(user);就可以執(zhí)行數(shù)據(jù)庫更新了
//6. 提交事務(wù)
transaction.commit();
//7. 關(guān)閉資源
session.close();
System.out.println("user:"+user);
}
二咪橙、 Hibernate的一級(jí)緩存
緩存的概念:介于應(yīng)用程序與永久性存儲(chǔ)的數(shù)據(jù)源之間夕膀,作用是降低應(yīng)用程序直接讀寫數(shù)據(jù)源的頻率,從而提高應(yīng)用的運(yùn)行性能。緩存中的數(shù)據(jù)是數(shù)據(jù)源數(shù)據(jù)的拷貝美侦。
1. 什么是Hibernate的一級(jí)緩存
- Hibernate的一級(jí)緩存就是指Session緩存,Session緩存就是一塊內(nèi)存空間产舞。
- 在使用Hibernate查詢對象時(shí),首先會(huì)拿該對象的OID去Session緩存中查找是否有匹配該OID值的對象。如果有就從Session緩存中取出使用,不再查詢數(shù)據(jù)庫音榜。如果沒有找到,就會(huì)去數(shù)據(jù)庫中查詢庞瘸。
- 當(dāng)從數(shù)據(jù)庫查詢到數(shù)據(jù)時(shí),也會(huì)在Session緩存區(qū)放置一份該對象的數(shù)據(jù)信息,下次再查詢就可以在Session緩存中直接查詢到。
@Test
//測試一級(jí)緩存的存在
public void test() {
//首先獲取到一個(gè)對象,再重復(fù)獲取該對象,查看會(huì)打印幾次sql語句
//1. 獲取Hibernate配置對象加載配置
//2. 獲取SessionFactory工廠對象
//3. 獲取Session對象
Session session = HibernateUtils.openSession();
//4. 開啟事務(wù)
Transaction transaction = session.beginTransaction();
//5. 實(shí)現(xiàn)業(yè)務(wù)邏輯
User user = session.get(User.class, 1);
System.out.println(user);
User user2 = session.get(User.class, 1);
System.out.println(user2);
User user3 = session.get(User.class, 1);
System.out.println(user3);
//6. 提交事務(wù)
transaction.commit();
//7. 釋放資源
session.close();
}
結(jié)果只執(zhí)行了一次查詢語句,說明Hibernate只去數(shù)據(jù)庫查詢了一次獲取到了user對象,然后將該對象的數(shù)據(jù)信息存入了Session緩存中,在這個(gè)Session沒有關(guān)閉前,都可以從緩存中直接取出與該OID匹配的user對象赠叼。
Hibernate的一級(jí)緩存(Session緩存)的特點(diǎn):
當(dāng)應(yīng)用程序調(diào)用Session接口的save()擦囊、update()违霞、saveOrUpdate()時(shí),如果緩存區(qū)中沒有對應(yīng)的對象,Hibernate會(huì)自動(dòng)的將從數(shù)據(jù)庫查詢到的相應(yīng)的對象信息加入到Session緩存中去瞬场。
當(dāng)調(diào)用Session接口的load()买鸽、get()、以及Query接口的list()方法時(shí),會(huì)判斷緩存中是否存在該對象,有則返回贯被,不會(huì)查詢數(shù)據(jù)庫眼五。如果緩存中沒有要查詢的對象,就去數(shù)據(jù)庫中查詢并放入Session緩存中。
當(dāng)調(diào)用Session對象的close()彤灶,Session緩存會(huì)被清空看幼。
2. Session緩存的快照區(qū)
Hibernate向一級(jí)緩存放入數(shù)據(jù)時(shí),同時(shí)會(huì)將一份數(shù)據(jù)放到Hibernate快照中,當(dāng)事務(wù)提交時(shí),
同時(shí)會(huì)清理Session的一級(jí)緩存,這時(shí)Hibernate會(huì)根據(jù)OID比較一級(jí)緩存與快照中的對象是否一致,
如果不一致執(zhí)行update語句。如果一致就不執(zhí)行幌陕。
Hibernate的快照確保了一級(jí)緩存中的數(shù)據(jù)與數(shù)據(jù)庫中數(shù)據(jù)的一致诵姜。
這也是Hibernate中持久化對象自動(dòng)更新數(shù)據(jù)庫的原理。
三搏熄、 Hibernate的事務(wù)控制
事務(wù):邏輯上的一組操作,組成這組操作的各個(gè)單元,要不全都成功,要不全都失敗棚唆。
1. 事務(wù)的四個(gè)特性:(ACID特性)
原子性(Automic):表示將事務(wù)所做的操作捆綁成一個(gè)不可分割的單元。對事務(wù)所進(jìn)行的數(shù)據(jù)修改等操作,要不全都成功,要不全都失敗心例。
一致性(Consistency):表示事務(wù)完成后,必須使所有的數(shù)據(jù)都保持一致狀態(tài)宵凌。
隔離性(Isolation):一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)干擾,并發(fā)執(zhí)行的事務(wù)之間不能互相干擾。
持久性(Durability):事務(wù)一旦提交,它對數(shù)據(jù)庫中數(shù)據(jù)的修改是永久性的止后。提交后的其他操作或者故障都不會(huì)有任何故障瞎惫。
2. 事務(wù)的并發(fā)問題
-
臟讀
一個(gè)事務(wù)提交到了另一個(gè)事務(wù)未提交的數(shù)據(jù)。這是很嚴(yán)重的并發(fā)問題,必須解決坯门。 例如: 用戶購物,付款尚未成功提交之前微饥,賣家就能讀到用戶付款的數(shù)據(jù),誤以為已經(jīng)付款。
-
不可重復(fù)讀
一個(gè)事務(wù)讀到了另一個(gè)事務(wù)已經(jīng)提交后的update的數(shù)據(jù),導(dǎo)致在同一個(gè)事務(wù)中的多次查詢結(jié)果不一致古戴。 例如: 小王在刷卡的同時(shí),家人用他的銀行卡進(jìn)行了網(wǎng)上購物,導(dǎo)致小王刷卡前后兩次查詢的結(jié)果不一致欠橘。
-
虛讀
一個(gè)事務(wù)都到了另一個(gè)事務(wù)已經(jīng)提交的insert的數(shù)據(jù),導(dǎo)致在同一個(gè)事務(wù)中的多次查詢結(jié)果不一致。
3. 事務(wù)的4個(gè)隔離級(jí)別
為了避免事務(wù)并發(fā)問題的發(fā)生,標(biāo)準(zhǔn)sql規(guī)范中定義了4個(gè)事務(wù)隔離級(jí)別,不同的隔離級(jí)別對事務(wù)的處理不同现恼。
- 讀未提交肃续。(Read Uncommitted,1級(jí)),一個(gè)事務(wù)可以訪問其他事務(wù)未提交的數(shù)據(jù)。
- 讀已提交叉袍。(Read Commited,2級(jí)),一個(gè)事務(wù)在執(zhí)行的過程中,可以訪問其他事務(wù)成功提交的新插入的數(shù)據(jù),也可以訪問成功修改的數(shù)據(jù)始锚。但禁止訪問未提交的數(shù)據(jù)。該隔離級(jí)別可以有效的防止臟讀喳逛。
- 可重復(fù)讀瞧捌。(Repeatable Read,4級(jí)), 一個(gè)事務(wù)在執(zhí)行的過程中,可以訪問其他事務(wù)成功提交的新插入的數(shù)據(jù),但不可以訪問成功修改的數(shù)據(jù)。此隔離級(jí)別可以有效的防止臟讀與不可重復(fù)讀姐呐。
- 序列化殿怜。(Serializable,8級(jí)),提供嚴(yán)格的事務(wù)隔離,事務(wù)只能序列化,一個(gè)一個(gè)的執(zhí)行曙砂,不能并發(fā)執(zhí)行头谜。此隔離級(jí)別可以防止臟讀,不可重復(fù)讀以及虛讀鸠澈。
隔離級(jí)別越高柱告,安全性越高,性能越低。
mysql的隔離級(jí)別默認(rèn)是可重復(fù)讀(Repeatable Read)
oracle的隔離級(jí)別默認(rèn)是可重復(fù)讀(Read Committed)
4. Hibernate的事務(wù)管理
<!--
設(shè)置隔離級(jí)別:
hibernate.connection.isolation = 4
1-Read uncommitted isolation
2-Read committed isolation
4-Repeatable read isolation
8-Serializable isolation
-->
<property name="hibernate.connection.isolation">4</property>
在使用Hibernate進(jìn)行事務(wù)管理時(shí),service層與dao層要保證Session對象的一致,可以采用三種方式確保Session
對象的一致: Session對象傳遞,使用ThreadLocal存儲(chǔ)與當(dāng)前線程綁定的Session對象,直接使用Hibernate封裝好的getCurrentSession()方法笑陈。
在這里,前兩種方式就省略了,如果有想了解的,可以翻看我以前寫的Connection部分JDBCUtils工具類的封裝际度。
直接使用Hibernate封裝好的管理Session的方式
在Hibernate的配置文件中,hibernate.current_session_context_class
屬性用于指定Session的管理方式:
- thread : Session對象的生命周期與當(dāng)前線程綁定
- jta : Session對象的生命周期與JTA事務(wù)綁定
- managed : Hibernate委托程序來管理Session的生命周期
在hibernate.cfg.xml
進(jìn)行如下配置:
<property name="hibernate.current_session_context_class">thread</property>
配置后,Hibernate提供了getCurrentThread()方法來創(chuàng)建一個(gè)與當(dāng)前線程綁定的Session對象。
在HibernateUtils工具類中添加getCurrentSession方法:
// 獲得當(dāng)前線程中的綁定的Session
// 注意:必須配置
// return
public static Session getCurrentSession() {
return sf.getCurrentSession();
}
需要注意的是:必須先在配置中進(jìn)行配置,而且使用后無需手動(dòng)關(guān)閉Session對象,事務(wù)提交后會(huì)自動(dòng)關(guān)閉Session對象
Sercice層:
//用戶轉(zhuǎn)賬的業(yè)務(wù)
public void transfer(String sender, String receiver, String amount) throws Exception {
Transaction transaction = null;
try {
//調(diào)用dao層
TransferDAO dao = new TransferDAOImpl();
//由于這里操作了兩條sql語句因此應(yīng)該開啟事務(wù)
Session session = HibernateUtils.getCurrentSession();
transaction = session.beginTransaction();
//轉(zhuǎn)出
dao.out(sender,amount);
//轉(zhuǎn)入
dao.in(receiver,amount);
//沒有異常就提交
transaction.commit();
} catch (Exception e) {
//回滾事務(wù)
transaction.rollback();
e.printStackTrace();
throw e;
}
}
dao 層:
// 轉(zhuǎn)出
public void out(String sender, String amount) throws SQLException {
Session session = HibernateUtils.getCurrentSession();
// 轉(zhuǎn)出
User user = session.get(User.class, 1);
double amount2 = Double.parseDouble(amount);
user.setAcount(user.getAcount() - amount2);
}
@Override
// 轉(zhuǎn)入
public void in(String receiver, String amount) throws SQLException {
Session session = HibernateUtils.getCurrentSession();
// 轉(zhuǎn)入
User user = session.get(User.class, 2);
double amount2 = Double.parseDouble(amount);
user.setAcount(user.getAcount() + amount2);
}
四涵妥、 Hibernate的批量查詢(概述)
1. HQL查詢 : Hibernate Query Language
HQL : Hibernate Query Language甲脏。Hibernate
的獨(dú)家查詢語言,屬于面向?qū)ο蟮牟樵冋Z言。
適用于:多表查詢,但不是很復(fù)雜時(shí)使用妹笆。
- setXxx : 如果HQL語句中有參數(shù),根據(jù)參數(shù)的不同類型設(shè)置參數(shù)的值。
- setParameter : 上面方法的萬金油版本娜氏∪可以根據(jù)參數(shù)自動(dòng)選擇參數(shù)的類型設(shè)置。
- uniqueResult : 結(jié)果只有一條記錄的時(shí)候使用,用于獲取唯一的結(jié)果贸弥。
- list : 獲取多條記錄存儲(chǔ)在List集合中窟坐。
- setFirstResult : 分頁查詢設(shè)置第一條記錄的位置。表示從第幾條數(shù)據(jù)查詢,默認(rèn)從0開始绵疲。
- setMaxResult : 分頁查詢設(shè)置結(jié)果集的最大記錄數(shù)哲鸳。即每頁顯示的最大數(shù)據(jù)數(shù)量。
使用HQL的步驟:
- 獲取Session對象,開啟事務(wù)
- 編寫HQL語句
- 使用Session對象獲取查詢對象Query
- 如果HQL語句包含參數(shù),使用query.setXxx()設(shè)置參數(shù)盔憨。
- 這里有一個(gè)萬金油的設(shè)置參數(shù)的方法. query.setParameter()徙菠;
- 執(zhí)行HQL查詢語句
HQL查詢測試:
/**
* Hibernate的HQL語句練習(xí)
*/
public class HibernateTest {
@Test
// HQL基本查詢
public void test() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:HQL的基本查詢
// 3.1 創(chuàng)建HQL查詢語句。HQL語句格式為:select * from 全類名.
// HQL語句格式為:select * from 全類名.
// 在查詢所有字段時(shí)可以省略select *
// String hql = "select * from com.itdream.domain.Customer";
String hql = "from Customer";
// 3.2 創(chuàng)建查詢對象Query
Query query = session.createQuery(hql);
// 3.3 執(zhí)行查詢
List<Customer> list = query.list();
// 如果確定結(jié)果為一條結(jié)果,可以使用uniqeResult()
// Customer customer = (Customer) query.uniqueResult();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// HQL條件查詢:問號(hào)占位符
public void test2() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:HQL條件查詢:問號(hào)占位符
// 3.1 編寫HQL查詢語句,注意:HQL語句中出現(xiàn)的是類中的屬性而不是表中的字段
String hql = "from Customer where cid = ?";
//3.2 獲取HQL的查詢對象Query
Query query = session.createQuery(hql);
//設(shè)置問號(hào)占位符處的參數(shù).Hibernate的問號(hào)占位付默認(rèn)從0開始
//query.setInteger(0, 2);
//萬金油的設(shè)置參數(shù)方法
query.setParameter(0, 2);
//3.3 執(zhí)行查詢
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// HQL條件查詢:命名占位符
public void test3() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:HQL條件查詢:命名占位符(冒號(hào):+命名)
// 3.1 編寫HQL查詢語句,注意:HQL語句中出現(xiàn)的是類中的屬性而不是表中的字段
String hql = "from Customer where cid = :cid";
//3.2 獲取HQL的查詢對象Query
Query query = session.createQuery(hql);
//設(shè)置問號(hào)占位符處的參數(shù).Hibernate的問號(hào)占位付默認(rèn)從0開始
//萬金油的設(shè)置參數(shù)方法
query.setParameter("cid", 2);
//3.3 執(zhí)行查詢
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// HQL分頁查詢
public void test4() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:HQL條件查詢:命名占位符(冒號(hào):+命名)
// 3.1 編寫HQL查詢語句,注意:HQL語句中出現(xiàn)的是類中的屬性而不是表中的字段
String hql = "from Customer";
//3.2 獲取查詢對象Query
Query query = session.createQuery(hql);
//3.3 設(shè)置分頁的參數(shù)
query.setFirstResult(4);//從第(4+1)條數(shù)據(jù)開始,Hibernate默認(rèn)從0開始
query.setMaxResults(2);//每頁顯示兩條數(shù)據(jù)
//3.4執(zhí)行hql語句
List<Customer> list = query.list();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
}
分頁查詢結(jié)果:
2. Critiria查詢
Criteria查詢是Hibernate的核心查詢對象郁岩。它是完全面向?qū)ο蟮臒o語句查詢婿奔。在Criteria查詢方式中,是絕對不會(huì)出現(xiàn)sql語句的。Criteria查詢又稱為QBC查詢(Query By Criteria)问慎。
適用于單表的條件查詢萍摊。
常用API
//獲取Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class); //傳入的參數(shù)是持久化類對象
//設(shè)置查詢條件
// 參數(shù)1:持久化類中的屬性 。 參數(shù)2:對應(yīng)的值
Criterion eq = Restrictions.eq("cid", 1);
//設(shè)置分頁參數(shù)
criteria.setFirstResult(4);//這里的4代表的是索引,第五條記錄開始
criteria.setMaxResults(2);//每頁顯示2條數(shù)據(jù)
//查詢總記錄數(shù)
criteria.setProjection(Projections.rowCount());
//執(zhí)行查詢
List<Customer> list = criteria.list();
Customer customer = (Customer) criteria.uniqueResult();
Criteria查詢的步驟:
- 獲取Session對象,開啟事務(wù)
- 獲取查詢對象
Criteria
- 如果有限制條件使用
Restrictions
添加限制條件 - 如果是分頁查詢使用
criteria.setFirstResult或setMaxResult
方法設(shè)置分頁參數(shù) - 將
Restrictions
設(shè)置的限制條件添加到查詢對象Criteria
中 - 執(zhí)行查詢
Criteria查詢測試:
@Test
// Criteria基本查詢 :查詢所有數(shù)據(jù)
public void test() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:Criteria的基本查詢
// 3.1 獲取Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class);
// 3.2 執(zhí)行查詢
List<Customer> list = criteria.list();
// Customer customer = (Customer) criteria.uniqueResult();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// Criteria條查詢
public void test2() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:Criteria的條件查詢
// 3.1 獲取Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class);
// 3.2 設(shè)置查詢限制條件
// 參數(shù)1:持久化類中的屬性 如叼。 參數(shù)2:對應(yīng)的值
Criterion eq = Restrictions.eq("cid", 1);
Criterion eq2 = Restrictions.eq("cname", "唐嫣");
// 添加限制條件到查詢對象中(可以添加多個(gè)限制條件)
criteria.add(eq);
criteria.add(eq2);
// 3.3 執(zhí)行查詢操作
// List<Customer> list = criteria.list();
Customer customer = (Customer) criteria.uniqueResult();
System.out.println(customer);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// Criteria分頁查詢
public void test3() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:Criteria的分頁查詢
// 3.1 獲取Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class);
//3.2 設(shè)置分頁參數(shù)
criteria.setFirstResult(4);//這里的4代表的是索引,第五條記錄開始
criteria.setMaxResults(2);//每頁顯示2條數(shù)據(jù)
//3.3 執(zhí)行查詢
List<Customer> list = criteria.list();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// Criteria查詢總記錄數(shù)
public void test4() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:Criteria的分頁查詢
// 3.1 獲取Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class);
// 3.2 獲取總記錄數(shù)
criteria.setProjection(Projections.rowCount());
//3.3 執(zhí)行查詢操作獲取總記錄數(shù)
Long rows = (Long) criteria.uniqueResult();
System.out.println(rows);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
附常用Restrictions的靜態(tài)方法:
常見的Restrictions的靜態(tài)方法
方法 說明
Restrictions.eq =
Restrictions.allEq 利用Map來進(jìn)行多個(gè)等于的限制
Restrictions.gt >(greater than)
Restrictions.ge >=(greater than or equal)
Restrictions.lt < (less than)
Restrictions.le <=(less than or equal)
Restrictions.between BETWEEN
Restrictions.like LIKE
Restrictions.in in
Restrictions.and and
Restrictions.or or
Restrictions.sqlRestriction 用SQL限定查詢
3. SQLQuery查詢(原生的SQL語句查詢)
適用于復(fù)雜的多表業(yè)務(wù)查詢
常用API:
//創(chuàng)建SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
//指定將結(jié)果集封裝到某個(gè)對象中
query.addEntity(Customer.class);
//執(zhí)行sql語句
List<Customer> list = query.list();
Customer customer = (Long)query.uniqueResult();
SQLQuery查詢測試:
@Test
// SQLQuery基本查詢 :查詢所有數(shù)據(jù)(返回Object數(shù)組的List)
public void test() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:SQLQuery的基本查詢:查詢所有數(shù)據(jù)
// 3.1 編寫sql語句
String sql = "select * from customer";
// 3.2 獲取SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
// 3.3 執(zhí)行查詢,返回的結(jié)果是一個(gè)List集合
// 每條記錄的查詢結(jié)果作為Object數(shù)組的元素冰木。將所有的記錄Object數(shù)組存入List集合
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// SQLQuery基本查詢 :查詢所有數(shù)據(jù)(返回Customer的List)
public void test2() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:SQLQuery的基本查詢:查詢所有數(shù)據(jù)
// 3.1 編寫sql語句
String sql = "select * from customer";
// 3.2 創(chuàng)建SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
// 3.3 指定將結(jié)果集封裝到某個(gè)對象中
query.addEntity(Customer.class);
// 3.4 執(zhí)行sql語句
List<Customer> list = query.list();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// SQLQuery條件查詢
public void test3() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:SQLQuery的基本查詢:查詢所有數(shù)據(jù)
// 3.1 編寫sql語句
String sql = "select * from customer where cid = ?";
// 3.2 創(chuàng)建SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
// 設(shè)置參數(shù)的值。參數(shù)1:第幾個(gè)數(shù)據(jù)。參數(shù)2:對應(yīng)的值
query.setParameter(0, 1);
// 3.3 指定將結(jié)果集封裝到某個(gè)對象中
query.addEntity(Customer.class);
// 3.4 執(zhí)行sql語句
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// SQLQuery分頁查詢:方式1:傳統(tǒng)sql語句
public void test4() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:SQLQuery的基本查詢:查詢所有數(shù)據(jù)
// 3.1 編寫sql語句
String sql = "select * from customer limit ?,?";
// 3.2 創(chuàng)建SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
// 設(shè)置分頁查詢的參數(shù)
query.setParameter(0, 4);
query.setParameter(1, 2);
// 3.3 指定將結(jié)果集封裝到某個(gè)對象中
query.addEntity(Customer.class);
// 3.4 執(zhí)行sql語句
List<Customer> list = query.list();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
@Test
// SQLQuery分頁查詢:方式2:setFirstResult()方法
public void test5() {
// 1. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 2.開啟事務(wù)
Transaction transaction = session.beginTransaction();
// -----------------------------------------
// 3. 業(yè)務(wù)邏輯:SQLQuery的基本查詢:查詢所有數(shù)據(jù)
// 3.1 編寫sql語句
String sql = "select * from customer";
// 3.2 創(chuàng)建SQLQuery查詢對象
SQLQuery query = session.createSQLQuery(sql);
// 設(shè)置分頁查詢的參數(shù)
query.setFirstResult(4);// 設(shè)置從第幾個(gè)數(shù)據(jù)開始查詢,默認(rèn)從0開始
query.setMaxResults(2);// 設(shè)置每頁顯示的數(shù)據(jù)條數(shù)
// 3.3 指定將結(jié)果集封裝到某個(gè)對象中
query.addEntity(Customer.class);
// 3.4 執(zhí)行sql語句
List<Customer> list = query.list();
System.out.println(list);
// -----------------------------------------
// 4.提交事務(wù)
transaction.commit();
// getCurrentSession無需手動(dòng)關(guān)閉
}
4. 簡單的CRM查詢案例
步驟:
1. 搭建工程環(huán)境
1. 創(chuàng)建工程,導(dǎo)入jar包,拷貝頁面等文件
2. 創(chuàng)建數(shù)據(jù)庫表cst_customer
3. 創(chuàng)建持久化類Customer
4. 創(chuàng)建持久化類和數(shù)據(jù)庫表的映射文件Customer.hbm.xml
5. 創(chuàng)建Hibernate的核心配置文件hibernate.cfg.xml
6. 完成核心配置文件中c3p0的配置,創(chuàng)建log4j.properties配置文件
7. 編寫工具類HibernateUtils踊沸,環(huán)境搭建完畢
1.1.導(dǎo)入jar包
包含有:
- 數(shù)據(jù)庫驅(qū)動(dòng)
- Hibernate必需包下的所有jar包
- Hibernate的c3p0中的3個(gè)jar包
- 日志集成slf4j和log4j的3個(gè)jar包
- jstl.jar與standard.jar的jstl標(biāo)簽庫jar包
1.2 創(chuàng)建數(shù)據(jù)庫表
CREATE DATABASE hibernate_crm;
USE hibernate_crm;
CREATE TABLE `cst_customer` (
`cust_id` BIGINT(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(hào)(主鍵)',
`cust_name` VARCHAR(32) NOT NULL COMMENT '客戶名稱(公司名稱)',
`cust_user_id` BIGINT(32) DEFAULT NULL COMMENT '負(fù)責(zé)人id',
`cust_create_id` BIGINT(32) DEFAULT NULL COMMENT '創(chuàng)建人id',
`cust_source` VARCHAR(32) DEFAULT NULL COMMENT '客戶信息來源',
`cust_industry` VARCHAR(32) DEFAULT NULL COMMENT '客戶所屬行業(yè)',
`cust_level` VARCHAR(32) DEFAULT NULL COMMENT '客戶級(jí)別',
`cust_linkman` VARCHAR(64) DEFAULT NULL COMMENT '聯(lián)系人',
`cust_phone` VARCHAR(64) DEFAULT NULL COMMENT '固定電話',
`cust_mobile` VARCHAR(16) DEFAULT NULL COMMENT '移動(dòng)電話',
PRIMARY KEY (`cust_id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO cst_customer(cust_id,cust_name)
VALUES(NULL,'唐嫣'),(NULL,'鐘漢良'),(NULL,'林心如'),
(NULL,'霍建華'),(NULL,'楊冪'),(NULL,'劉愷威'),
(NULL,'高圓圓'),(NULL,'趙又廷');
1.3 創(chuàng)建持久化類
與數(shù)據(jù)庫表基本保持一致歇终,按照持久化類的編寫規(guī)則編寫。
1.4 創(chuàng)建持久化類和數(shù)據(jù)庫表的映射文件Customer.hbm.xml
步驟:
- 在持久化類的同級(jí)目錄下,創(chuàng)建xml文件,取名類名.hbm.xml雕沿。這里名字為:
Customer.hbm.xml
- 導(dǎo)入DTD約束练湿。從jar包中可以找到DTD的約束描述,copy過來
- 創(chuàng)建持久化類與數(shù)據(jù)庫表的映射
- 創(chuàng)建持久化類中標(biāo)識(shí)符OID與數(shù)據(jù)庫表的主鍵的映射
- 創(chuàng)建類中普通屬性與數(shù)據(jù)庫表的字段的映射
<?xml version="1.0" encoding="UTF-8"?>
<!-- 建立持久化類Customer與數(shù)據(jù)庫表customer的映射關(guān)系的配置文件 -->
<!-- 引入DTD約束 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立持久化類與表的映射關(guān)系 -->
<class name="com.itdream.domain.Customer" table="cst_customer">
<!-- 配置持久化類OID與表的主鍵的映射 -->
<id name="cust_id" column="cust_id">
<!-- 配置主鍵生成策略 -->
<generator class="native"></generator>
</id>
<!-- 配置普通字段的映射關(guān)系 -->
<property name="cust_name" column="cust_name"></property>
</class>
</hibernate-mapping>
1.5 創(chuàng)建Hibernate的核心配置文件hibernate.cfg.xml
步驟:
- 在src目錄下創(chuàng)建文件名為
hibernate.cfg.xml
的配置文件 - 導(dǎo)入DTD約束
- 配置Hibernate連接數(shù)據(jù)庫的基本配置
- 配置Session與當(dāng)前線程綁定
- 配置Hibernate基本屬性,包括:
- Hibernate方言,根據(jù)這個(gè)配置Hiberante使用對應(yīng)的sql語句,實(shí)現(xiàn)了跨數(shù)據(jù)庫
- 顯示SQL語句
- 格式化SQL語句
- 配置Hibernate對應(yīng)數(shù)據(jù)庫表的生成方式
hbm2ddl
- 配置數(shù)據(jù)庫的隔離級(jí)別
- c3p0連接池的配置
- 加載映射文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 導(dǎo)入Hibernate核心配置文件的DTD約束 -->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<!-- 配置Hibernate的核心配置文件 -->
<hibernate-configuration>
<session-factory>
<!--1. Hibernate連接數(shù)據(jù)庫的基本配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_crm</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--2. Session與本地線程綁定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!--3. Hibernate的基本屬性配置 -->
<!-- Hibernate的方言配置,Hibernate根據(jù)這個(gè)配置生成對應(yīng)的SQL語句,從而實(shí)現(xiàn)跨數(shù)據(jù)庫 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 顯示SQL語句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL語句 -->
<property name="hibernate.format_sql">true</property>
<!-- Hibernate對數(shù)據(jù)庫表的生成方式,hbm2ddl -->
<property name="hibernate.hbm2ddl.auto">none</property>
<!-- 配置隔離級(jí)別 :4 讀可重復(fù)(Repeatable read) -->
<property name="hibernate.connection.isolation">4</property>
<!-- C3P0連接池的配置 -->
<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<!-- 最小連接 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 最大連接數(shù) -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 連接超時(shí)時(shí)長 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 每120秒檢查空閑連接 -->
<property name="hibernate.c3p0.idle_test_period">120</property>
<!-- 最大statments數(shù)量 -->
<property name="hibernate.c3p0.max_statements">120</property>
<!-- 連接用完后审轮,每次增加的連接數(shù) -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都驗(yàn)證連接是否可用 -->
<property name="hibernate.c3p0.validate">false</property>
<!--4. 加載映射文件 -->
<mapping resource="com/itdream/domain/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
1.6 完成核心配置文件中c3p0的配置,創(chuàng)建log4j.properties配置文件
1. c3p0的配置見上一條1.5中核心配置文件.
2. log4j日志集成的配置文件log4j.properties
在src目錄下創(chuàng)建log4j.properties:
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info, stdout,file
1.7 編寫工具類HibernateUtils
/**
* 初始化SessionFactory,提供Session對象的Hibernate工具類
*/
public class HibernateUtils {
private static SessionFactory sf = null;
static {
// 創(chuàng)建Hibernate配置對象,加載src目錄下默認(rèn)的hibernate.cfg.xml配置文件
Configuration configuration = new Configuration().configure();
// 創(chuàng)建SessionFactory工廠對象
sf = configuration.buildSessionFactory();
// 程序關(guān)閉銷毀SessionFactory對象
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("程序關(guān)閉銷毀SessionFactory對象");
sf.close();
}
}));
}
/**
* 獲取Session對象的方法
*/
public static Session openSession() {
return sf.openSession();
}
/**
* 獲取與當(dāng)前線程綁定的Session對象
*/
public static Session getCurrentSession() {
return sf.getCurrentSession();
}
}
2. 代碼實(shí)現(xiàn),使用Hibernate的查詢語句查詢所有Customer
2.1 mennu.jsp修改a標(biāo)簽跳轉(zhuǎn)
<TD class=menuSmall><A class=style2 href="customer?method=list"target=main>- 客戶列表</A></TD>
2.2 創(chuàng)建Servlet,映射url-pattern為servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 獲取傳遞過來的method參數(shù)
String method = request.getParameter("method");
if ("list".equals(method)) { // 如果是list,就查詢所有Customer客戶
try {
// 調(diào)用service層
CustomerService service = new CustomerServiceImpl();
List<Customer> list = service.findAllCustomers();
// 存入request域
request.setAttribute("list", list);
System.out.println(list);
// 轉(zhuǎn)發(fā)
request.getRequestDispatcher("/jsp/customer/list.jsp").forward(request, response);;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
2.3 CustomerService層,調(diào)用dao層查詢所有Customer
@Override
public List<Customer> findAllCustomers() throws SQLException {
//調(diào)用dao層查詢所有Customer用戶
CustomerDAO dao = new CustomerDAOImpl();
return dao.findAllCustomers();
}
2.4 CustomerDAO層,查詢所有Customer返回
使用Criteria與HQL兩種查詢方式,單表查詢推薦使用Criteria查詢
@Override
// 方式1:顯示所有Customer的方法:Criteria查詢(單表查詢簡單)
public List<Customer> findAllCustomers() throws SQLException {
// 1. 獲取配置對象加載配置文件
// 2. 獲取SessionFactory對象
// 3. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 4. 開啟事務(wù)
Transaction transaction = session.beginTransaction();
// 5. 業(yè)務(wù)邏輯 :查詢所有Customer對象,單表查詢使用Criteria較為簡單
// 5.1 創(chuàng)建Criteria查詢對象
Criteria criteria = session.createCriteria(Customer.class);
// 5.2 如果有條件就添加限制條件Restrictions,然后添加到查詢對象中
// 5.3 執(zhí)行查詢
List<Customer> list = criteria.list();
// 6. 提交事務(wù)
transaction.commit();
// 7. getCurrentSession()無需手動(dòng)關(guān)閉Session對象
return list;
}
/*@Override
// 方式2:顯示所有Customer的方法:HQL查詢(常用于不是很復(fù)雜的多表查詢)
public List<Customer> findAllCustomers() throws SQLException {
// 1. 獲取配置對象加載配置文件
// 2. 獲取SessionFactory對象
// 3. 獲取Session對象
Session session = HibernateUtils.getCurrentSession();
// 4. 開啟事務(wù)
Transaction transaction = session.beginTransaction();
// 5. 業(yè)務(wù)邏輯 : 查詢所有Customer對象,單表查詢使用Criteria較為簡單
// 5.1 編寫HQL語句,HQL語句中出現(xiàn)的都是持久化類中的屬性,而不是數(shù)據(jù)庫表中的字段
String hql = "from Customer";
// 5.2 創(chuàng)建HQL的Query對象
Query query = session.createQuery(hql);
// 5.3 如果hql語句中有參數(shù)使用setParameter()設(shè)置參數(shù)
// 5.4 執(zhí)行hql語句
List<Customer> list = query.list();
// 6. 提交事務(wù)
transaction.commit();
// 7. getCurrentSession()無需手動(dòng)關(guān)閉Session對象
return list;
}*/
2.5 查詢結(jié)果肥哎,list頁面解析(這里省略)
查詢結(jié)果圖: