Hibernate 事物
Hibernate是對JDBC的輕量封裝,主要功能是操作數據庫。
Hibernate中的事物管理
在Hibernate中,可以通過API接口來操作管理事物。可以通過session.beginTransaction()開啟一個事物,持久化操作后,通過commit()提交事物。如果事物異常,通過rollback()來進行事物的回滾。
除了在代碼中對事物開啟,提交和回滾操作外,還可以在Hibernate的配置文件中對事物進行配置。配置文件中,可以設置事物的隔離級別。
- 在hibernate.cfg.xml文件中的<session-factory>標簽元素中進行配置
<!--配置數據庫隔離級別
0001 1 讀未提交
0010 2 讀已提交
0100 4 可重復讀
1000 8 串行
-->
<property name="hibernate.connection.isolation ">4</property>
基本點:在項目中如何管理事物:
在項目中,通過經驗我們有一個基本的認識:
在業務開始之前打開事物,在業務執行之后提交事物,執行過程中如果出現異常,則回滾事物
- 在dao層操作數據庫的時候需要用到session對象,在service控制事物也是使用session對象完成,所以我們要確保dao層和service層使用的是同一個session對象
注意1:調用getCurrentSession方法必須配合主配置中的一段配置
<!--指定session與當前線程綁定-->
<property name="current_session_context_class">thread</property>
注意2:通過getCurrentSession方法獲得的Session對象,當事物提交時,session會自動關閉,不需要手動調用close關閉,session會自動被回收
Hibernate 查詢API
HQL查詢
HQL(Hibernate Query Language) 是面向對象的查詢語言。使用的是類、對象和屬性的概念。沒有表和字段的概念。Hibernate提供的Query接口是專門的HQL查詢接口,能夠執行各種復雜的HQL查詢語句。
由于HQL是面向對象的,所以不會出現和表名列名有關的語句。應該使用的是對象名 屬性名
- 完整的HQL語句
select...from...where...group...by...having...order by...asc/desc
當檢索數據表中的所有記錄時,查詢語句中可以省略select關鍵字
獲得Hibernate的Session對象
編寫HQL語句
調用session.createQuery 創建查詢對象
通過Query的setXxx設置參數
調用Query對象的list()或uniqueResult()執行查詢
查詢所有記錄
//編寫HQL語句
String hql = "from cn.probuing.domain.Customer";
//根據HQL語句創建查詢對象
Query query = session.createQuery(hql);
//根據查詢對象獲得
List<Customer> list = query.list();//返回list
排序查詢
/**
* 排序語法
*/
@Test
public void HQLSort(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
String hql = "from cn.probuing.domain.Customer order by cust_id desc";
Query query = session.createQuery(hql);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
根據條件進行查詢
/**
* 條件查詢
*/
@Test
public void HQLCondition(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "from cn.probuing.domain.Customer order where cust_id=:id";//另一種寫法
Query query = session.createQuery(hql2);
//設置占位符
// query.setParameter(0,2);
//另一種占位符寫法
query.setParameter("id",2);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
分頁查詢
/**
* 分頁查詢
*/
@Test
public void HQLPage(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "from cn.probuing.domain.Customer";//另一種寫法
Query query = session.createQuery(hql2);
//表示從0條開始
query.setFirstResult(0);
//表示查找2條
query.setMaxResults(2);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
session.close();
}
聚合函數
/**
* 聚合函數
*/
@Test
public void HQLCount() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// String hql = "from cn.probuing.domain.Customer order where cust_id=?";
String hql2 = "select count(*) from cn.probuing.domain.Customer";
//求和 指定列名
String hql3 = "select sum(cust_id) from cn.probuing.domain.Customer";
String hql4 = "select avg(cust_id) from cn.probuing.domain.Customer";
String hql5 = "select max(cust_id) from cn.probuing.domain.Customer";
String hql6 = "select min(cust_id) from cn.probuing.domain.Customer";
Query query = session.createQuery(hql4);
Number number = (Number) query.uniqueResult();
System.out.println(number);
tx.commit();
session.close();
}
投影查詢
查詢對象的某一個屬性
@Test
public void testHQLDemo2() {
Session session = HibernateUtils.openSession();
//開啟事物
Transaction transaction = session.beginTransaction();
//編寫HQL語句
// String hql = "from cn.probuing.domain.Customer where cust_id =? ";
String hql = "from cn.probuing.domain.Customer where cust_id = :cust_id ";
//根據HQL語句創建查詢對象
Query query = session.createQuery(hql);
//設置參數 指定類型
// query.setLong(0,1l);
//設置參數 不指定參數
// query.setParameter(0,1l);
//根據參數名設置參數
query.setParameter("cust_id", 1l);
//根據查詢對象獲得
Customer customer = (Customer) query.uniqueResult();//接收唯一的查詢結果
System.out.println(customer.toString());
//提交事物,關閉資源
transaction.commit();
session.close();
}
在指定條件時有以下幾個方法:
- 指定參數需要使用setXxx()指定類型
- 不指定參數需要使用setParameter(占位符索引,值)
- 根據名稱指定條件值 setparameter(名稱,值)
分頁查詢
hql語句中沒有limit(?,?)這樣的語句,需要使用API方法來實現分頁的功能
- setFirstResult() 設置起始的位置
- setMaxResult() 設置最大的條數
public void testHQLDemo3() {
Session session = HibernateUtils.openSession();
//開啟事物
Transaction transaction = session.beginTransaction();
String hql = "from cn.probuing.domain.Customer ";
//根據HQL語句創建查詢對象
Query query = session.createQuery(hql);
//設置起始信息
query.setFirstResult(0);
//設置最大條數
query.setMaxResults(2);
//根據查詢對象獲得
List<Customer> list = query.list();
System.out.println(list.toString());
//提交事物,關閉資源
transaction.commit();
session.close();
}
Criteria查詢
Criteria是一個完全面向對象,可擴展的條件查詢API,通過它完全不需要考慮數據庫底層如何實現,以及SQL語句如何編寫。Criteria查詢又稱為QBC查詢。它是Hibernate的另一種對象檢索方式
org.hibernate.criterion.Criterion是Hibernate提供的一個面向對象查詢條件接口。一個單獨的查詢就是Criterion接口的一個實例。用于限制Criteria對象的查詢。在Hibernate中Criterion對象的創建時通過Restriction工廠類完成
主要步驟:
(1) 獲得Hibernate的Session對象
(2) 通過Session獲得Criteria對象
(3) 使用Restriction的靜態方法創建Criterion條件對象。Restrictions類中提供了一系列用于設定查詢條件的靜態方法
(4) 向Criteria對象中添加Criterion查詢條件
基本查詢
//獲得session
Session session = HibernateUtils.openSession();
//通過session獲得Criteria對象 參數表示指定查詢所有的Customer對象
Criteria criteria = session.createCriteria(Customer.class);
//使用Restrictions對象進行查詢 返回集合
List<Customer> list = criteria.list();
//返回單個結果
// Customer customer = (Customer) criteria.uniqueResult();
System.out.println(list.toString());
條件查詢
@Test
public void testHQLDemo4() {
//獲得session
Session session = HibernateUtils.openSession();
//通過session獲得Criteria對象 參數表示指定查詢所有的Customer對象
Criteria criteria = session.createCriteria(Customer.class);
//調用add方法添加參數 => 查詢cust_id 為1的Customer對象
criteria.add(Restrictions.eq("cust_id", 1l));
// 條件:>
//使用Restrictions對象進行查詢 返回集合
// List<Customer> list = criteria.list();
//返回單個結果
Customer customer = (Customer) criteria.uniqueResult();
System.out.println(customer.toString());
session.close();
}
對應條件API:
分頁查詢
/**
* Criteria 查詢
*/
@Test
public void testHQLDemo4() {
//獲得session
Session session = HibernateUtils.openSession();
//通過session獲得Criteria對象 參數表示指定查詢所有的Customer對象
Criteria criteria = session.createCriteria(Customer.class);
//指定起始
criteria.setFirstResult(0);
criteria.setMaxResults(2);
// 使用Restrictions對象進行查詢 返回集合
List<Customer> list = criteria.list();
System.out.println(list.toString());
session.close();
}
查詢總記錄數
@Test
public void testHQLDemo4() {
//獲得session
Session session = HibernateUtils.openSession();
//通過session獲得Criteria對象 參數表示指定查詢所有的Customer對象
Criteria criteria = session.createCriteria(Customer.class);
//設置查詢的聚合函數
criteria.setProjection(Projections.rowCount());
Long result = (Long) criteria.uniqueResult();
System.out.println(result);
session.close();
}
排序查詢
@Test
public void BaseCriteriaOrder() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//操作數據
//創建criteria
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("cust_id"));
// criteria.addOrder(Order.desc("cust_id"));
List list = criteria.list();
System.out.println(list);
tx.commit();
session.close();
}
原生SQL查詢
普通查詢
@Test
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//開啟事物
Transaction tx = session.beginTransaction();
//書寫SQL語句
String sql = "select * from cst_customer";
//創建查詢對象
SQLQuery query = session.createSQLQuery(sql);
//封裝對象:將結果集指定封裝對象
query.addEntity(Customer.class);
//查詢結果 接收封裝對象集合
// List<Customer> list = query.list();
//查詢結果 未指定封裝對象
List<Object[]> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
條件查詢
@Test
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//開啟事物
Transaction tx = session.beginTransaction();
//書寫SQL語句
String sql = "select * from cst_customer where cust_id = ?";
//創建查詢對象
SQLQuery query = session.createSQLQuery(sql);
//設置參數
query.setParameter(0, 1);
//指定封裝對象
query.addEntity(Customer.class);
List<Customer> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
分頁查詢
public void sqlQuery() {
Session session = HibernateUtils.openSession();
//開啟事物
Transaction tx = session.beginTransaction();
//書寫SQL語句
String sql = "select * from cst_customer limit ?,? ";
//創建查詢對象
SQLQuery query = session.createSQLQuery(sql);
//設置條件參數
query.setParameter(0, 0);
query.setParameter(1,1);
//封裝對象:將結果集指定封裝對象
query.addEntity(Customer.class);
//查詢結果 接收封裝對象集合
List<Customer> list = query.list();
//查詢結果 未指定封裝對象
// List<Object[]> list = query.list();
System.out.println(list.toString());
tx.commit();
session.close();
}
離線查詢
DetachedCriteria翻譯為離線條件查詢,它可以脫離session來使用的一種條件查詢對象
-
傳統的查詢方式過于依賴session對象。減少參數的傳遞。
離線查詢
使用離線查詢思路為:
在web層或者service層不依賴session創建查詢對象Criteria。并設置好條件等相關參數
傳遞Criteria對象到Dao層
Dao層將離線的Criteria對象與session關聯。關聯后會將離線的Criteria對象轉換為普通的Criteria對象。
通過普通的Criteria對象執行數據操作
實例代碼
@Test
public void fun1() {
//模擬service層或web層
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//拼裝好條件
detachedCriteria.add(Restrictions.idEq(2l));
//dao層
Session session = HibernateUtils.openSession();
//離線對象關聯session 關聯session后 就會由離線的Criteria對象變為普通的Criteria對象
Criteria c = detachedCriteria.getExecutableCriteria(session);
//執行查詢
List<Customer> list = c.list();
System.out.println(list);
}
查詢優化
類級別查詢優化
延遲加載
類級別的延遲指的是查詢某個對象的時候,是否采用有延遲。通常在<class>標簽上配置lazy屬性,lazy屬性的默認值是true
- lazy:true 加載時,不查詢,使用時才查詢
- lazy:false 加載時立即查詢
<class name="Customer" table="cst_customer" lazy="true">
- load方法 在執行時不發送任何sql語句,返回一個對象,使用該對象時,才執行查詢
Customer c = session.load(Customer.class,2l);
原理解釋
在加載時,返回的是代理對象 代理對象會在使用對象屬性時,根據關聯的session查詢數據庫,加載數據
注意 使用懶加載時要確保,調用屬性加載數據時,session是打開的 還沒有關閉。否則會拋出異常
關聯級別查詢優化
關聯級別查詢優化
關聯級別就是指對象的關聯屬性,分為兩種:集合級別的關聯。對象級別的關聯
集合級別的關聯策略
- lazy:延遲加載
lazy屬性:延遲加載
true:默認值 延遲加載
false:立即加載
extra:極其懶惰 與懶加載效果基本一致,如果只獲得集合的size,只查詢集合的size(count語句) -
fetch:抓取策略
fetch屬性:決定加載策略,使用什么類型的sql語句加載集合數據
select:單表查詢加載
join:使用多表查詢加載集合 此種情況下 lazy屬性失效 相當于立即加載 多表數據會直接全部加載
subselect:使用子查詢加載集合
集合屬性策略
對象屬性級別的關聯策略
主要作用于<many-to-one>
- lazy
- false: 立即加載
- proxy: 代理加載 由指定的代理決定加載策略
- fetch
- select: 使用單表查詢
-
join: 使用多表查詢
關聯屬性策略
我們總結來說就是:fetch主要控制抓取關聯對象的時候發送SQL語句的格式的lazy主要控制查詢其關聯對象的時候是否采用延遲加載的
為了提高效率:fetch的選擇應該選擇select lazy的取值應該選擇true
批量抓取
<!--
batch-size:抓取集合的數量為3
-->
<set name="linkMens" inverse="true" batch-size="3">