1. 程式人生 > >二:hibernate的持久化類和物件識別符號

二:hibernate的持久化類和物件識別符號

二 hibernate的持久化類和物件識別符號
1.1持久化類的編寫規範
1.1.1什麼是持久化類:
Hibernate是持久層的ORM對映框架,專注於資料的持久化工作。所謂的持久化,就是將記憶體中的資料永久儲存到關係型資料庫中。那麼知道了什麼是持久化,什麼又是持久化類呢?其實所謂的持久化類指的是一個Java類與資料庫表建立了對映關係,那麼這個類稱為是持久化類。其實你可以簡單的理解為持久化類就是一個Java類有了一個對映檔案與資料庫的表建立了關係。那麼我們在編寫持久化類的時候有哪些要求呢?接下來我們來看一下:
1.1.2持久化類的編寫規則:
我們在編寫持久化類的時候需要有以下幾點需要注意:
持久化類需要提供無引數的構造方法。因為在Hibernate的底層需要使用反射生成類的例項。
持久化類的屬性需要私有,對私有的屬性提供公有的get和set方法。因為在Hibernate底層會將查詢到的資料進行封裝。
持久化類的屬性要儘量使用包裝類的型別。因為包裝類和基本資料型別的預設值不同,包裝類的型別語義描述更清晰而基本資料型別不容易描述。舉個例子:
假設表中有一列員工工資,如果使用double型別,如果這個員工工資忘記錄入到系統中,系統會將預設值0存入到資料庫,如果這個員工工資被扣完了,也會向系統中存入0.那麼這個0就有了多重含義,而如果使用包裝類型別就會避免以上情況,如果使用Double型別,忘記錄入工資就會存入null,而這個員工工資被扣完了,就會存入0,不會產生歧義。
持久化類要有一個唯一標識OID與表的主鍵對應。因為Hibernate中需要通過這個唯一標識OID區分在記憶體中是否是同一個持久化類。在Java中通過地址區分是否是同一個物件的,在關係型資料庫的表中是通過主鍵區分是否同一條記錄。那麼Hibernate就是通過這個OID來進行區分的。Hibernate是不允許在記憶體中出現兩個OID相同的持久化物件的。
持久化類儘量不要使用final進行修飾。因為Hibernate中有延遲載入的機制,這個機制中會產生代理物件,Hibernate產生代理物件使用的是位元組碼的增強技術完成的,其實就是產生了當前類的一個子類物件實現的。如果使用了final修飾持久化類。那麼就不能產生子類,從而就不會產生代理物件,那麼Hibernate的延遲載入策略(是一種優化手段)就會失效。.
持久化類我們已經可以正常編寫了,但是在持久化類中需要有一個唯一標識OID與表的主鍵去建立對映關係。而且主鍵一般我們是不會讓客戶手動錄入的,一般我們是由程式生成主鍵。那麼Hibernate中也提供了相應的主鍵生成的方式,那麼我們來看下Hibernate的主鍵生成策略。
簡單的說:
我們的實體類都需要遵從JavaBean的編寫規範。
什麼是JavaBean:
Bean:在軟體開發領域,Bean表示可重用元件。
JavaBean就是用java語言開發的可重用元件。
JavaBean的編寫規範是什麼:
類都是public的
都有預設無參建構函式
成員變數都是私有的
都有公有的get/set方法
一般都實現Serializable介面。
基本型別和包裝類的選擇問題:
由於包裝類可以有null值。所以實際開發中都是用包裝類。
1.2hibernate中物件識別符號(OID)
OID全稱是Object Identifier,又叫做物件識別符號。
它是hibernate用於區分兩個物件是否是同一個物件的標識。
我們都知道,虛擬機器記憶體區分兩個物件看的是記憶體的地址是否一致。資料庫區分兩個物件,靠的是表的主鍵。hibernate負責把記憶體中的物件持久化到資料庫表中,靠的就是物件識別符號來區分兩個物件是否是同一個。實體類中對映主鍵的欄位就是OID,如下圖所示:
這裡寫圖片描述


1.3hibernate的主鍵生成策略
在講解Hibernate的主鍵生成策略之前,先來了解兩個概念,即自然主鍵和代理主鍵,具體如下:
自然主鍵:把具有業務含義的欄位作為主鍵,稱之為自然主鍵。例如在customer表中,如果把name欄位作為主鍵,其前提條件必須是:每一個客戶的姓名不允許為null,不允許客戶重名,並且不允許修改客戶姓名。儘管這也是可行的,但是不能滿足不斷變化的業務需求,一旦出現了允許客戶重名的業務需求,就必須修改資料模型,重新定義表的主鍵,這給資料庫的維護增加了難度。

代理主鍵:把不具備業務含義的欄位作為主鍵,稱之為代理主鍵。該欄位一般取名為“ID”,通常為整數型別,因為整數型別比字串型別要節省更多的資料庫空間。在上面例子中,顯然更合理的方式是使用代理主鍵。
這裡寫圖片描述

Hibernate的一級快取和物件狀態
2.1hibernate的一級快取
2.1.1hibernate中的一級快取:
Hibernate的一級快取就是指Session快取,Session快取是一塊記憶體空間,用來存放相互管理的java物件,在使用Hibernate查詢物件的時候,首先會使用物件屬性的OID值在Hibernate的一級快取中進行查詢,如果找到匹配OID值的物件,就直接將該物件從一級快取中取出使用,不會再查詢資料庫;如果沒有找到相同OID值的物件,則會去資料庫中查詢相應資料。當從資料庫中查詢到所需資料時,該資料資訊也會放置到一級快取中。Hibernate的一級快取的作用就是減少對資料庫的訪問次數。

在 Session 介面的實現中包含一系列的 Java 集合, 這些 Java 集合構成了 Session 快取。只要 Session 例項沒有結束生命週期,存放在它快取中的物件也不會結束生命週期。固一級快取也被稱為是Session基本的快取。

Hibernate的一級快取有如下特點:
當應用程式呼叫Session介面的save()、update()、saveOrUpdate時,如果Session快取中沒有相應的物件,Hibernate就會自動的把從資料庫中查詢到的相應物件資訊加入到一級快取中去。
當呼叫Session介面的load()、get()方法,以及Query介面的list()、iterator()方法時,會判斷快取中是否存在該物件,有則返回,不會查詢資料庫,如果快取中沒有要查詢物件,再去資料庫中查詢對應物件,並新增到一級快取中。
當呼叫Session的close()方法時,Session快取會被清空。
2.1.2測試一級快取
@Test
// 證明Hibernate的一級快取的存在:

public void demo1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();        
        Customer customer1 = session.get(Customer.class, 1l);/

/ 馬上發生一條sql查詢1號客戶.並將資料存入了一級快取

System.out.println(customer1);
        Customer customer2 = session.get(Customer.class, 1l);

// 沒有發生SQL語句從一級快取中獲取資料.

System.out.println(customer2);
System.out.println(customer1 == customer2);// true 一級快取快取的是物件的地址.
        tx.commit();
        session.close();
    }

2.1.3快照機制:
Hibernate 向一級快取放入資料時,同時複製一份資料放入到Hibernate快照中,當使用commit()方法提交事務時,同時會清理Session的一級快取,這時會使用OID判斷一級快取中的物件和快照中的物件是否一致,如果兩個物件中的屬性發生變化,則執行update語句,將快取的內容同步到資料庫,並更新快照;如果一致,則不執行update語句。Hibernate快照的作用就是確保一級快取中的資料和資料庫中的資料一致。

資料庫中的資料:

程式程式碼:

@Test
    public void test2(){    
        Customer c2 = null;//記憶體中的一個物件
        //1.獲取Session物件
        Session s = HibernateUtil.openSession();
        //2.使用Session物件開啟事務
        Transaction tx = s.beginTransaction();
        //3.執行查詢:查詢ID為2的客戶物件
        c2 = s.get(Customer.class, 2L);
        System.out.println(c2);//custName
        //修改客戶名稱為:文正大廈
        c2.setCustName("文正大廈");
        System.out.println(c2);//custName:文正大廈
        //4.提交事務
        tx.commit();
        //5.關閉Session
        s.close();          
        //當程式走到此處時,一級快取就沒了,但是並不影響我繼續使用客戶物件
        System.out.println(c2);//custName到底是什麼
    }

問題:
custName輸出的到底是什麼?
分析:
如果是,則表示我們修改的程式碼沒啟任何作用,廢程式碼一行。
如果輸出是文正大廈,則表示我們程式記憶體的資料可能和資料庫表中的不一致了,那就是髒資料。
思考:
有沒有可能輸出的是文正大廈,並且資料庫的資料也變成了文正大廈呢?
如果真的發生了這種情況,是如何做到的呢?
答案:

2.2物件的三種狀態
2.2.1物件的狀態說明:
瞭解了主鍵的生成策略之後,我們可以進一步來了解持久化類了。Hibernate為了更好的來管理持久化類,特將持久化類分成了三種狀態。在Hibernate中持久化的物件可以劃分為三種狀態,分別是瞬時態、持久態和脫管態,一個持久化類的例項可能處於三種不同狀態中的某一種,三種狀態的詳細介紹如下。
1、瞬時態(transient)
瞬時態也稱為臨時態或者自由態,瞬時態的例項是由new命令建立、開闢記憶體空間的物件,不存在持久化標識OID(相當於主鍵值),尚未與Hibernate Session關聯,在資料庫中也沒有記錄,失去引用後將被JVM回收。瞬時狀態的物件在記憶體中是孤立存在的,與資料庫中的資料無任何關聯,僅是一個資訊攜帶的載體。
2、持久態(persistent)
持久態的物件存在持久化標識OID ,加入到了Session快取中,並且相關聯的Session沒有關閉,在資料庫中有對應的記錄,每條記錄只對應唯一的持久化物件,需要注意的是,持久態物件是在事務還未提交前變成持久態的。
3、脫管態(detached)
脫管態也稱離線態或者遊離態,當某個持久化狀態的例項與Session的關聯被關閉時就變成了脫管態。脫管態物件存在持久化標識OID,並且仍然與資料庫中的資料存在關聯,只是失去了與當前Session的關聯,脫管狀態物件發生改變時Hibernate不能檢測到。
2.2.2學習物件狀態我們要明確的:
a、是為了更好的掌握hibernate中操作的方法。
b、區分狀態只有兩個標識
一是否有OID
二是否和Session建立的關係
臨時狀態:
沒有OID,和Session沒有關係。
持久化狀態:
有OID,和Session有關係。
脫管狀態:
有OID,和Session沒有關係。
第3章Hibernate的事務控制
3.1配置Session和執行緒繫結
在Hibernate中,可以通過程式碼來操作管理事務,如通過“Transaction tx = session.beginTransaction();”開啟一個事務;持久化操作後,通過“tx.commit();”提交事務;如果事務出現異常,又通過“tx.rollback();”操作來撤銷事務(事務回滾)。
除了在程式碼中對事務開啟,提交和回滾操作外,還可以在Hibernate的配置檔案中對事務進行配置。配置檔案中,可以設定事務的隔離級別。其具體的配置方法是在hibernate.cfg.xml檔案中的標籤元素中進行的。配置方法如下所示。
這裡寫圖片描述

hibernate.connection.isolation = 4 
1Read uncommitted isolation
2Read committed isolation
4—Repeatable read isolation
8—Serializable isolation

–>
4
到這我們已經設定了事務的隔離級別,那麼我們在真正進行事務管理的時候,需要考慮事務的應用的場景,也就是說我們的事務控制不應該是在DAO層實現的,應該在Service層實現,並且在Service中呼叫多個DAO實現一個業務邏輯的操作。具體操作如下顯示:

其實最主要的是如何保證在Service中開啟的事務時使用的Session物件和DAO中多個操作使用的是同一個Session物件。
其實有兩種辦法可以實現:
可以在業務層獲取到Session,並將Session作為引數傳遞給DAO。
可以使用ThreadLocal將業務層獲取的Session繫結到當前執行緒中,然後在DAO中獲取Session的時候,都從當前執行緒中獲取。

其實使用第二種方式肯定是最優方案,那麼具體的實現已經不用我們來完成了,Hibernate的內部已經將這個事情做完了。我們只需要完成一段配置即可。
Hibernate5中自身提供了三種管理 Session 物件的方法
Session 物件的生命週期與本地執行緒繫結
Session 物件的生命週期與 JTA 事務繫結
Hibernate 委託程式管理 Session 物件的生命週期

在 Hibernate 的配置檔案中, hibernate.current_session_context_class 屬性用於指定 Session 管理方式, 可選值包括
thread:Session 物件的生命週期與本地執行緒繫結
jta:Session 物件的生命週期與 JTA 事務繫結
managed:Hibernate 委託程式來管理 Session 物件的生命週期

配置步驟:
    1、在hibernate.cfg.xml檔案中配置


thread
2、獲取Session時使用的方法:
/**
* 每次都是從當前執行緒上獲取Session
* @return
*/
public static Session getCurrentSession(){
return factory.getCurrentSession();
}
細節:
當我們把Session繫結到當前執行緒之後,關閉session就是hibernate來做的,我們就不用關了。
到這裡我們已經對Hibernate的事務管理有了基本的瞭解,但是之前我們所做的CRUD的操作其實還沒有查詢多條記錄。那如果我們需要查詢多條記錄要如何完成呢,我們接下來去學習一下Hibernate的其他的相關的API。

第4章Hibernate查詢物件的API
4.1Query:(掌握)
4.1.1概述
Query代表面向物件的一個Hibernate查詢操作。在Hibernate中,通常使用session.createQuery()方法接受一個HQL語句,然後呼叫Query的list()或uniqueResult()方法執行查詢。所謂的HQL是Hibernate Query Language縮寫,其語法很像SQL語法,但它是完全面向物件的。
在Hibernate中使用Query物件的步驟,具體所示:
(1)獲得Hibernate的Session物件。
(2)編寫HQL語句。
(3)呼叫session.createQuery 建立查詢物件。
(4)如果HQL語句包含引數,則呼叫Query的setXxx設定引數。
(5)呼叫Query物件的方法執行查詢。
HQL的說明:
把表的名稱換成實體類名稱。把表字段名稱換成實體類屬性名稱。
例如:
SQL:select * from cst_customer where cust_name like ?
HQL:select * from Customer where custName = ?
其中select * 可以省略,寫為:from Customer where custName = ?
瞭解了使用Query物件的步驟後,接下來,通過具體示例來演示Query物件的查詢操作。
4.1.2常用查詢:
4.1.2.1基本查詢
/**
* 查詢所有
*/

@Test
    public void test1(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.獲取Query物件
        Query query = s.createQuery("from Customer");
        //2.執行物件的方法,獲取結果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }   

4.1.2.2條件查詢
/**
* 條件查詢
* hibernate的引數佔位符索引是從0開始的
*/

@Test
    public void test2(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.獲取Query物件
        Query query = s.createQuery("from Customer where custName like ? and custLevel = ?");
        //2.給引數佔位符賦值
        query.setString(0, "%集%");
        query.setString(1, "普通客戶");
        //3.執行物件的方法,獲取結果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }
/**
 * 條件查詢
 *  給引數佔位符提供一個具體的名稱
 *  引數佔位符的寫法:
 *      :名稱
 *  賦值的時候不需要寫冒號,直接寫名稱
 */
@Test
    public void test3(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        //1.獲取Query物件
        Query query = s.createQuery("from Customer where custName like :custName and custLevel = :custLevel");
        //2.給引數佔位符賦值
        query.setString("custName", "%集%");
        query.setString("custLevel", "普通客戶");
        //3.執行物件的方法,獲取結果集
        List list = query.list();
        for(Object o : list){
            System.out.println(o);
        }
        tx.commit();
    }       

4.1.2.3分頁查詢
/**
* 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();
    }       

4.1.2.4排序查詢
/**
* 排序查詢
* 使用的關鍵字:
* order by
* 升序:
* asc 預設值
* 降序:
* desc
*/

@Test
    public void test2(){
        Session s = HibernateUtil.getCurrentSession();
        Transaction tx = s.beginTransaction();
        Query query = s.createQuery("from LinkMan order by lkmId desc ");
        List list = query.list();
        for(Object o : list){;
            System.out.println(o);
        }
        tx.commit();
    }           

4.1.2.5統計查詢
/**
* 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();
}               

4.1.2.6投影查詢
/**
* 投影查詢:
* 投影:使用一個實體的部分欄位資訊,來構建實體類物件,叫做物件的投影(在hibernate中的叫法)
* 使用HQL的方式查詢實體類的部分欄位資訊,並且封裝到實體類中。(QBC也能實現投影查詢,但是不如hql的好用,所以使用投影查詢,一般都用HQL)
* HQL語句的寫法:
* select new Customer() from Customer
* 如果工程只有一個唯一的類,可以不寫全限定類名,否則必須寫全限定類名。
* 實體類要求:
* 必須提供一個相同引數列表的建構函式
*/

@Test
public void test3(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    Query query = s.createQuery("select new Customer(custId,custName) from Customer ");
    List<Object[]> list = query.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}               

/**
* 客戶的實體類
*/

public class Customer implements Serializable {

    private Long custId;
    private String custName;
    private String custSource;
    private String custIndustry;
    private String custLevel;
    private String custAddress;
    private String custPhone;

    public Customer(){

    }
//提供對應引數列表的建構函式
public Customer(Long custId, String custName) {
        this.custId = custId;
        this.custName = custName;
    }

    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }
    public Set<LinkMan> getLinkmans() {
        return linkmans;
    }
    public void setLinkmans(Set<LinkMan> linkmans) {
        this.linkmans = linkmans;
    }
    @Override
    public String toString() {
        return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
                + ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
                + ", custPhone=" + custPhone + "]";
    }   
}

4.1.3Query中的方法說明:
list方法:該方法用於查詢語句,返回的結果是一個list集合。
uniqueResult方法:該方法用於查詢,返回的結果是一個Object物件。
setter方法:Query介面中提供了一系列的setter方法用於設定查詢語句中的引數,針對不同的資料型別,需要用到不同的setter方法。
uniqueResult()方法:該方法用於返回唯一的結果,在確保只有一條記錄的查詢時可以使用該方法。
setFirstResult()方法:該方法可以設定獲取第一個記錄的位置,也就是它表示從第幾條記錄開始查詢,預設從0開始計算。
setMaxResult()方法:該方法用於設定結果集的最大記錄數,通常與setFirstResult()方法結合使用,用於限制結果集的範圍,以實現分頁功能。

4.2Criteria:
4.2.1概述
Criteria是一個完全面向物件,可擴充套件的條件查詢API,通過它完全不需要考慮資料庫底層如何實現,以及SQL語句如何編寫,它是Hibernate框架的核心查詢物件。Criteria 查詢,又稱為QBC查詢(Query By Criteria),它是Hibernate的另一種物件檢索方式。
org.hibernate.criterion.Criterion是Hibernate提供的一個面向物件查詢條件介面,一個單獨的查詢就是Criterion介面的一個例項,用於限制Criteria物件的查詢,在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物件的查詢操作。
4.2.2常用查詢:
4.2.2.1基本查詢
/**
* 查詢所有
*/

@Test
public void test1(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.獲取Criteria物件
    Criteria c = s.createCriteria(Customer.class);//它就相當於HQL的from Customer
    //2.執行物件的方法獲取結果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}   

4.2.2.2條件查詢
/**
* 條件查詢
*/

@Test
public void test2(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.獲取Criteria物件
    Criteria c = s.createCriteria(Customer.class);//它就相當於HQL的from Customer
    //2.設定查詢條件
    c.add(Restrictions.like("custName", "%集%"));//from Customer where custName  like "%集%"
    c.add(Restrictions.eq("custLevel", "普通客戶"));
    //3.執行物件的方法獲取結果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}   

4.2.2.3分頁查詢
/**
* 分頁查詢
* 和HQL是一模一樣的
*/

@Test
public void test3(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.獲取Criteria物件
    Criteria c = s.createCriteria(Customer.class);//它就相當於HQL的from Customer
    //2.設定分頁
    c.setFirstResult(2);
    c.setMaxResults(2);
    //3.執行物件的方法獲取結果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}       

4.2.2.4排序查詢
/**
* 排序查詢
*/

@Test
public void test1(){
    Session s = HibernateUtil.getCurrentSession();
    Transaction tx = s.beginTransaction();
    //1.獲取物件
    Criteria c = s.createCriteria(Customer.class);
    //2.設定排序
    c.addOrder(Order.desc("custId"));
    //3.獲取結果集
    List list = c.list();
    for(Object o : list){
        System.out.println(o);
    }
    tx.commit();
}           

4.2.2.5統計查詢
/**
* 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();
}           

4.2.2.6離線查詢
/**
* 離線條件查詢
* 離線:
* 它是和線上對應的。
* 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;
}               

第5章附錄:QBC常用查詢條件說明
短語 含義
Restrictions.eq 等於=
Restrictions.allEq 使用Map,使用key/value進行多個等於的判斷
Restrictions.gt 大於>
Restrictions.ge 大於等於>=
Restrictions.lt 小於<
Restrictions.le 小於等於<=
Restrictions.between 對應sql的between子句
Restrictions.like 對應sql的like子句
Restrictions.in 對應sql的in子句
Restrictions.and and 關係
Restrictions.or or關係
Restrictions.sqlRestriction Sql限定查詢
Restrictions.asc() 根據傳入的欄位進行升序排序
Restrictions.desc() 根據傳入的欄位進行降序排序

運算型別 HQL運算子 QBC運算方法
比較運算 = Restrictions.eq()
<> Restrictions.not(Restrictions.eq())

= Restrictions.ge()
< Restrictions.lt()
<= Restrictions.le()
is null Restrictions.isNull()
is not null Restrictions.isNotNull()
範圍運算子 in Restrictions.in()
not in Restrictions.not(Restrictions.in())
between Restrictions.between()
not between Restrictions.not(Restrictions.between())

運算型別 HQL運算子 QBC運算方法
字串模式匹配 like Restrictions.like()
邏輯 and Restrictions.and()|
Restrictions.conjunction()
or Restrictions.or()|
Restrictions.disjunction()
not Restrictions.not()

相關推薦

:hibernate持久化物件識別符號

二 hibernate的持久化類和物件識別符號 1.1持久化類的編寫規範 1.1.1什麼是持久化類: Hibernate是持久層的ORM對映框架,專注於資料的持久化工作。所謂的持久化,就是將記憶體中的資料永久儲存到關係型資料庫中。那麼知道了什麼是持久化,什

hibernate持久化物件識別符號

一丶什麼是持久化類: Hibernate是持久層的ORM對映框架,專注於資料的持久化工作。所謂的持久化,就是將記憶體中的資料永久儲存到關係型資料庫中。那麼知道了什麼是持久化,什麼又是持久化類呢? 持久化類 = 實體類 + 對映檔案。 其實所謂的持久化類指的是一個Jav

hibernate持久化一級緩存

包括 ide 讀取 持久化類 沒有 imp mysql- final enc 持久化類編寫規則 1.有無參構造函數。 2.屬性不能被final修飾。 3.對外提供屬性的get和set方法。 4.需要提供一個持久化OID對象唯一標識對象。 主鍵生成策略

Scala學習筆記():物件

object object 是隻有一個例項的類。它的定義與Java中的class類似,如: // 單例物件 object AppEntry { def main(args: Array[String]): Unit = { print("Hello World!") } }

C++學習筆記():物件

類是物件共性的抽象,一種自定義的資料型別,可認為是C語言中結構體的拓展。它的作用是將資料和演算法(資料操作)封裝在使用者自定義的抽象資料型別中。 為什麼要在C++中新增類這樣一種“工具“呢? 程式中的每一組資料都是為某一種操作而準備的。而資料的交叉使用容易導致資料被誤操作,

python四十:物件

類有資料屬性和函式屬性, 但物件只有資料屬性。  def funName(args): '函式文件字串' 函式體 class 類名: '類的文件字串' 類體 建立一個類 class foo: pass 用類foo例項

C++學習筆記 () ---- 物件

①、類和物件 類的定義,如下: class Student{ public: //成員變數 char *name; int age; float score; //成員函式 void say(){ cout<<

Java基礎 實驗物件

1.實驗目的 掌握類的宣告、物件的建立、方法的定義和呼叫、建構函式的使用。 2.實驗內容 1)定義一個表示學生資訊的類Student,要求如下: ① 類Student的成員變數:       sNO 表示學號;      

hibernate持久化代理主鍵

Hibernate的持久化類 持久化類:就是一個java類(編寫的JavaBean),這個java類與表建立了對映關係就可以成為是持久化類。 * 持久化類=JavaBean + xxx.hbm.xm

Scala 程式設計—第七節:物件()

前言:         類和物件第二節,主要介紹:單例物件、伴生物件與伴生類、apply方法、抽象類 1.單例物件 Java語言中,如果想直接使用類名點的方式呼叫方法或屬性,直接用static修飾即可。但Scala語言不支援靜態成員,而提供了object物件,這

Scala入門到精通——第七節:物件

本節主要內容 單例物件 伴生物件與伴生類 apply方法 應用程式物件 抽象類 單例物件 在某些應用場景下,我們可能不需要建立物件,而是想直接呼叫方法,但是Scala語言並不支援靜態成員,Scala通過單例物件來解決該問題。單例物件的建立方式如下:

C++面向物件- -物件的使用(

  目錄 物件指標 1、指向物件的指標 2、指向物件成員的指標 3、指向當前物件的 this 指標 共用資料的保護 1、常物件 2、常物件成員 3、指向物件的常指標 4、指向常物件的指標 5、物件的常引用 6、const 型資料小結

手寫spring:Java反射獲取物件資訊全解析

反射在這裡的作用就是知道全路徑 在框架啟動的時候把類例項化 然後設定到@service 和@Autowired裡面 所以要了解這東西怎麼用的 1. 什麼是類物件 類物件,就是用於描述這種類,都有什麼屬性,什麼方法的 2. 獲取類物件 獲取類物件有3種方式 (1). Class.f

c++物件

1、函式過載: 函式名相同,引數列表不同(引數個數或引數型別不同)void f();void f(int x);void f(int x,int y);    僅僅是返回值不同,不能是函式過載  

C++第八章 物件

【專案1 - 三角形類】下面設計一個三角形類,請給出各成員函式的定義 #include<iostream> #include<cmath> using namespace std; class Triangle {public: void Set

java知識總結(物件

java總結二 類和物件 首先建一個Demo類作為示例 public class Demo {//類 //屬性(成員變數) private int sex;//私有的成員變數 //方法(成員函式) public int getSex() { return se

用Java實現JVM():支援介面、物件

1. 概述我的 JVM 已經能夠執行HelloWorld了,並且有了基本的 JVM 骨架,包括執行時資料結構的定義(棧、棧幀、運算元棧等),執行時的邏輯控制等。但它還沒有類和物件的概念,比如無法執行下面這更復雜的HelloWorld:public interface SpeakerInterface {

【C++】物件

 一、this指標  關於this指標的一個精典回答:       當你進入一個房子後,       你可以看見桌子、椅子、地板等,       但是房子你是看不到全貌了。       對於一個類的例項來說,       你可以看到它的成員函式、成員變數,       但是例

【C++】物件

定義成員函式 所有成員都必須在類內宣告,但是成員函式可以定義在類內也可以定義在類外。 std::string isbn() const { return bookno;} ??? isbn函式是如何獲得bookno成員所依賴的物件呢?緊隨引數列表之後

C++學習筆記——物件

設計一個類就是設計一個新的型別,應該考慮: 此型別的“合法值”是什麼? 此型別應該有什麼樣的函式和操作符? 新型別的物件該如何被建立和銷燬? 如何進行物件的初始化和賦值? 物件作為函式的引數如何以值傳遞? 誰將使用此型別的物件成員? 類定義的語法形式: clas