它是hibernate用於區分兩個對象是否是同一個對象的標識。
我們都知道,虛擬機內存區分兩個對象看的是內存的地址是否一致。數據庫區分兩個對象,靠的是表的主鍵。hibernate負責把內存中的對象持久化到數據庫表中,靠的就是對象標識符來區分兩個對象是否是同一個。實體類中映射主鍵的字段就是OID 在映射文件中對應數據庫主鍵的屬性
自然主鍵:把具有業務含義的字段作為主鍵,稱之為自然主鍵。
代理主鍵:把不具備業務含義的字段作為主鍵,稱之為代理主鍵。該字段一般取名為“ID”,通常為整數類型,因為整數類型比字符串類型要節省更多的數據庫空間。在上面例子中,顯然更合理的方式是使用代理主鍵
1.1.1 hibernate中的一級緩存:
Hibernate的一級緩存就是指Session緩存,Session緩存是一塊內存空間,用來存放相互管理的java對象,在使用Hibernate查詢對象的時候,首先會使用對象屬性的OID值在Hibernate的一級緩存中進行查找,如果找到匹配OID值的對象,就直接將該對象從一級緩存中取出使用,不會再查詢數據庫;如果沒有找到相同OID值的對象,則會去數據庫中查找相應數據。當從數據庫中查詢到所需數據時,該數據信息也會放置到一級緩存中。Hibernate的一級緩存的作用就是減少對數據庫的訪問次數。
Hibernate的一級緩存有如下特點:
當應用程序調用Session接口的save()、update()、saveOrUpdate時,如果Session緩存中沒有相應的對象,Hibernate就會自動的把從數據庫中查詢到的相應對象信息加入到一級緩存中去。
當調用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法時,會判斷緩存中是否存在該對象,有則返回,不會查詢數據庫,如果緩存中沒有要查詢對象,再去數據庫中查詢對應對象,並添加到一級緩存中。
當調用Session的close()方法時,Session緩存會被清空。
1.1.1 快照機制:
Hibernate 向一級緩存放入數據時,同時復制一份數據放入到Hibernate快照中,當使用commit()方法提交事務時,同時會清理Session的一級緩存,這時會使用OID判斷一級緩存中的對象和快照中的對象是否一致,如果兩個對象中的屬性發生變化,則執行update語句,將緩存的內容同步到數據庫,並更新快照;如果一致,則不執行update語句。Hibernate快照的作用就是確保一級緩存
中的數據和數據庫中的數據一致。
1、 瞬時態(transient)
瞬時態也稱為臨時態或者自由態,瞬時態的實例是由new命令創建、開辟內存空間的對象,不存在持久化標識OID(相當於主鍵值),尚未與Hibernate Session關聯,在數據庫中也沒有記錄,失去引用后將被JVM回收。瞬時狀態的對象在內存中是孤立存在的,與數據庫中的數據無任何關聯,僅是
一個信息攜帶的載體。
2、 持久態(persistent)
持久態的對象存在持久化標識OID ,加入到了Session緩存中,並且相關聯的Session沒有關閉,在數據庫中有對應的記錄,每條記錄只對應唯一的持久化對象,需要注意的是,持久態對象是在事務還未提交前變成持久態的。
3、 脫管態(detached)
脫管態也稱離線態或者游離態,當某個持久化狀態的實例與Session的關聯被關閉時就變成了脫管態。脫管態對象存在持久化標識OID,並且仍然與數據庫中的數據存在關聯,只是失去了與當前Session的關聯,脫管狀態對象發生改變時Hibernate不能檢測到。
、區分狀態只有兩個標識
一是否有OID
二是否和Session建立的關系
臨時狀態:
沒有OID,和Session沒有關系。
持久化狀態:
有OID,和Session有關系。
脫管狀態:
有OID,和Session沒有關系。
其實最主要的是如何保證在Service中開啟的事務時使用的Session對象和DAO中多個操作使用的是同一個Session對象。
其實有兩種辦法可以實現:
可以在業務層獲取到Session,並將Session作為參數傳遞給DAO。
可以使用ThreadLocal將業務層獲取的Session綁定到當前線程中,然后在DAO中獲取Session的時候,都從當前線程中獲取。
1.1.1.1 統計查詢
/**
* HQL使用聚合函數:
* 統計查詢
* 聚合函數:
* count sum max min avg
*
* sql語句使用聚合函數時,在不使用group by子句的情況下,返回的結果,永遠只有一行一列的情況。
*
* 在SQL語句時:
* select count(*) from table 它是統計所有字段,效率沒有只統計主鍵字段高
* select count(主鍵) from table 它和第一個的結果是一樣的,但是效率更高
* select count(非主鍵) from table 只統計不為null的字段
*/
@Test
public void test1(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
Query query = s.createQuery("select count(lkmId) from LinkMan");//它最終仍然換轉成SQL語句
// List list = query.list();
// for(Object o : list){;
// System.out.println(o);
// }
Long total = (Long)query.uniqueResult();//返回的是一個唯一的結果集。 只有確定結果集唯一時,才能使用
System.out.println(total);
tx.commit();
}
1.1.1.1 分頁查詢
/**
* mysql的分頁關鍵字
* limit
* limit的參數含義
* 第一個:查詢的開始記錄索引
* 第二個:每次查詢的條數
* hibernate中針對分頁提供了兩個方法
* setFirstResult(int firstResult);設置開始記錄索引
* setMaxResults(int maxResults);設置每次查詢的記錄條數
*/
@Test
public void test4(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//1.獲取Query對象
Query query = s.createQuery("from Customer");
//2.設置分頁的方法
query.setFirstResult(2);
query.setMaxResults(2);
//3.執行對象的方法,獲取結果集
List list = query.list();
for(Object o : list){
System.out.println(o);
}
tx.commit();
}
在Hibernate中Criterion對象的創建通常是通過Restrictions 工廠類完成的,它提供了條件查詢方法。
通常,使用Criteria對象查詢數據的主要步驟,具體如下:
(1)獲得Hibernate的Session對象。
(2)通過Session獲得Criteria對象。
(3)使用Restrictions的靜態方法創建Criterion條件對象。Restrictions類中提供了一系列用於設定查詢條件的靜態方法,這些靜態方法都返回Criterion實例,每個Criterion實例代表一個查詢條件。
(4)向Criteria對象中添加Criterion 查詢條件。Criteria的add()方法用於加入查詢條件。
(5)執行Criterita的 list() 或uniqueResult() 獲得結果。
細節:
HQL能查的,QBC都能查,反之亦然。
了解了Criteria對象的使用步驟后,接下來,通過具體示例來演示Criteria對象的查詢操作。
1.1.1.1 離線查詢
/**
* 離線條件查詢
* 離線:
* 它是和在線對應的。
* Criteria對象是一個在線對象,它是由一個可用的(活動的)Session對象獲取的出來的。
* 當session失效時,就無法再獲取該對象了。
* 有一個對象,它也可以用於設置條件,但是獲取的時候並不需要Session對象。
* 該對象就叫做離線對象:
* DetachedCriteria對象
* 使用該對象進行的查詢就叫做:離線查詢
*
* 如何獲取該對象
* DetachedCriteria dCriteria = DetachedCriteria.forClass(要查詢的實體類字節碼);
*
*/
@Test
public void test3(){
//模擬一次web操作: 瀏覽器發送請求——調用servlet——調用service——調用dao——拿到結果到jsp上展示
List list = servletFindAllCustomer();
for(Object o : list){
System.out.println(o);
}
}
//模擬servlet
public List<Customer> servletFindAllCustomer(){
//離線對象
DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
//設置條件:和Criteria是一樣的
dCriteria.add(Restrictions.like("custName","%集%"));
return serviceFindAllCustomer(dCriteria);
}
public List<Customer> serviceFindAllCustomer(DetachedCriteria dCriteria) {
return daoFindAllCustomer(dCriteria);
}
public List<Customer> daoFindAllCustomer(DetachedCriteria dCriteria) {
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//把離線對象使用可用Session激活
Criteria c = dCriteria.getExecutableCriteria(s);
List<Customer> list = c.list();
tx.commit();
return list;
}
1.1.1.1 統計查詢
/**
* QBC使用聚合函數
* 統計查詢
* 涉及的對象:
* Criteria
* 涉及的方法:
* setProjection(Projection p);
* 參數的含義
* Projection:要添加的查詢投影
*/
@Test
public void test2(){
Session s = HibernateUtil.getCurrentSession();
Transaction tx = s.beginTransaction();
//1.獲取對象
Criteria c = s.createCriteria(Customer.class);//from Customer | select * from cst_customer
//2.想辦法把select * 變成 select count(*)
// c.setProjection(Projections.rowCount());//select count(*)
c.setProjection(Projections.count("custId"));//select count(cust_id)
//3.獲取結果集
// List list = c.list();
// for(Object o : list){
// System.out.println(o);
// }
Long total = (Long)c.uniqueResult();
System.out.println(total);
tx.commit();
}