JAVAEE框架學習——Hibernate——事務 查詢API應用、查詢優化

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">
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 本文包括:1、Hibernate 的查詢方式2、HQL (Hibernate Query Language) 查詢...
    廖少少閱讀 2,688評論 0 15
  • hibernate(20170731) 1.導包:hibernate-distribution-3.5.6-Fin...
    瀟湘雨smile閱讀 555評論 0 0
  • Hibernate: 一個持久化框架 一個ORM框架 加載:根據特定的OID,把一個對象從數據庫加載到內存中OID...
    JHMichael閱讀 1,995評論 0 27
  • 每年的這個時間大家都在忙碌著籌辦圣誕節。這是時候當圣誕樹出來,所有的裝飾品都被掛好后,整個圣誕節氣氛完全呈現出來。...
    打豆豆閱讀 646評論 0 2
  • ——春天的主旋律 世事無常,熱愛本職工作的我卻被迫換到了另一個崗位,丟失了自己的專業,也丟掉了曾經為...
    春天的主旋律閱讀 309評論 3 4