1. 程式人生 > >從零打造線上網盤系統之Hibernate查詢與更新技術

從零打造線上網盤系統之Hibernate查詢與更新技術

歡迎瀏覽Java工程師SSH教程從零打造線上網盤系統系列教程,本系列教程將會使用SSH(Struts2+Spring+Hibernate)打造一個線上網盤系統,本系列教程是從零開始,所以會詳細以及著重地闡述SSH三個框架的基礎知識,第四部分將會進入專案實戰,如果您已經對SSH框架有所掌握,那麼可以直接瀏覽第四章,原始碼均提供在GitHub/ssh-network-hard-disk上供大家參閱

本章學習目標

  1. 掌握標準查詢API的使用
  2. 掌握QBE
  3. 掌握HQL
  4. 掌握SQL

本篇前言

在前面兩篇文章中我們基本會使用Hibernate操作資料庫,但是基本都是使用的是Session介面進行操作,像這種根據索引進行檢索資料庫侷限性非常大.為此Hibernate提供了很強大的查詢技術,例如標準查詢API,QBE,HQL,SQL等

標準查詢API

要想使用標準查詢API就要用到Hibernate的org.hibernate.Criteria介面,通過Session.createCriteria既可以建立Criteria物件

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(Product.class);
        criteria.setMaxResults(2);
        List list = criteria.list();
        for (Object var : list) {
            System.out.print(var.toString());
        }
        session.close();
    }

在使用標準API進行查詢的時候增加約束條件是一個SimpleExpression物件,由org.hibernate.criterion.Restrictions類的靜態方法可以獲得相應的SimpleExpression物件.

criteria.add(Restrictions.eq("name", "中藥"));

我們同樣可以進行模糊匹配

criteria.add(Restrictions.like("name", "%中%"));

使用MatchMode類靜態常量,模糊匹配我們也可以這樣也是一樣的

criteria.add(Restrictions.like("name", "中", MatchMode.ANYWHERE));

在增加查詢的約束條件的時候我們會這樣使用,查詢成績大於90的學生並且是女生,或者怎麼怎麼樣....,我們可以使用LogicalExpression改變他們的邏輯

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(Product.class);
        SimpleExpression id1 = Restrictions.eq("id", 1);
        SimpleExpression id11 = Restrictions.eq("id", 11);
        LogicalExpression logicalExpression = Restrictions.or(id1, id11);
        criteria.add(logicalExpression);
        List list = criteria.list();
        for (Object var : list) {
            System.out.print(var.toString());
        }
        session.close();
    }

可以看到使用LogicalExpression邏輯變得非常臃腫,Hibernate提供了更便捷的解決方案,那就是使用Conjunction生成And關係,使用Disjunction生成or關係

        Disjunction disjunction = Restrictions.disjunction();
        disjunction.add(id1);
        disjunction.add(id11);
        criteria.add(disjunction);
        Conjunction conjunction = Restrictions.conjunction();
        conjunction.add(id1);
        conjunction.add(id11);
        criteria.add(conjunction);

那麼如何使用標準查詢API進行分頁查詢呢?得益於Hibernate對不同資料庫的封裝,我們可以很便捷地進行分頁,例如xxxxx limit0, 10這樣的SQL我們平時經常見到,我們可以使用Criteria介面兩條語句即可實現分頁功能

        criteria.setFirstResult(0);
        criteria.setMaxResults(10);

您閱讀到這裡的時候可以發現Criteria介面返回的都是List物件,如果我們知道一條索引id,我們根絕這個id去進行去進行查詢,就沒必要返回給我一個List集合了吧? 同樣我們可以使用uniqueResult方法返回一個Object物件

        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(Product.class);
        criteria.add(Restrictions.eq("id",1));
        Product product = (Product) criteria.uniqueResult();

在處理多個實體Bean關聯的情況下我們需要處理多個Criteria之間的關聯,我們可以通過Criteria建立另一個Criteria物件,引數是一個屬性名

        Session session = HibernateSessionFactory.getSession();
        Criteria productCriteria = session.createCriteria(Product.class);
        Criteria productDetailCriteria = productCriteria.createCriteria("productDetail");
        productDetailCriteria.add(Restrictions.eq("detatil", "肯定匹配不到我"));
        List list = productCriteria.list();

我們可以使用AggregateProjection類進行聚合操作查詢,例如查詢一個表中的記錄數

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(Product.class);
        criteria.setProjection(Projections.rowCount());
        Long count = (Long) criteria.uniqueResult();
    }

QBE(Query By Example)

除了使用標準查詢API,我們還可以使用QBE進行查詢

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Criteria criteria = session.createCriteria(Product.class);
        Product product = new Product();
        product.setName("中藥");
        criteria.add(Example.create(product));
        List list = criteria.list();
    }

HQL(Hibernate Query Language)

HQL是Hibernate框架提供的另一種操作資料的方式,其語法非常接近SQL,但卻是面向物件的也就是說HQL所操作的都是持久化物件,而不是資料表

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Query from_product = session.createQuery("from Product");
        List list = from_product.list();
    }

我們在進行復雜的查詢HQL都是遊刃有餘的

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Query from_product = session.createQuery("select name from Product where id >0 or id<10");
        List list = from_product.list();
    }

HQL和JDBC一樣是支援佔位符查詢的

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Query from_product = session.createQuery("select name from Product where id > :id");
        from_product.setInteger("id", 0);
        List list = from_product.list();
    }

HQL進行分頁查詢跟標準查詢API很是相似

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Query from_product = session.createQuery("from Product");
        from_product.setFirstResult(0);
        from_product.setMaxResults(10);
        List list = from_product.list();
    }

HQL同樣支援聚合查詢

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        Query from_product = session.createQuery("select count(*) from Product");
        Long count = (Long) from_product.uniqueResult();
    }

HQL作為一種查詢語言同樣支援Update/Delete/Insert

    Query from_product = session.createQuery("xxxxxxx");
    from_product.executeUpdate();

SQL

雖然HQL可以完成大多數的操作,但是HQL並不支援資料庫的所有特性,因此在需要的時候我們還是需要直接使用SQL操作資料庫

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        NativeQuery sqlQuery = session.createSQLQuery("select * from products p");
        sqlQuery.addEntity("p", Product.class);
        List<Product> list = sqlQuery.list();
    }

本篇總結

掌握Hibernate的查詢與更新技術,能在Hibernate框架的任意場景中熟練運用各種查詢與更新技術