Hibernate入门-04

今天内容

    1. Hibernate的查询方式
    2. Hibernate的查询策略优化

Hibernate的查询方式(5种)

OID查询

 session.get(对象.class,OID)
 session.load(对象.class,OID)

对项属性导航查询

查询一个客户会将客户中的联系人(关联属性)信息一块查出来
    LinkMan l1 = (LinkMan)session.get(LinkMan.class,1l);
    Customer c = l1.getCustomer();

HQL

概述

<!---->
1. HQL的介绍
    * HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似
      但是它使用的是类对象和属性的概念,而没有表跟字段的概念
    * 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式

2. HQL与SQL的关系
    * HQL 查询语句是面向对象的,Hibernate负责解析HQL查询语句,然后根据对象-关系映射文件中的映射信息, 
       把 HQL 查询语句翻译成相应的 SQL 语句. 
    * HQL 查询语句中的主体是域模型中的类及类的属性
    * SQL 查询语句是与关系数据库绑定在一起的. SQL查询语句中的主体是数据库表及表的字段

完整的HQL语句结构

select ... form ... where ... group by ...having ... order by ... asc/desc

基本查询

HQL基本的查询格式
    * 支持方法链的编程,即直接调用list()方法
    * 简单的代码如下
        * String hql = "select * from  cn.itcast.domain.Customer ";//完整写法
        * session.createQuery("from Customer").list();

使用别名的方式
    * 可以使用别名的方式(给类名设置别名)
        * session.createQuery("from Customer c").list();
        * session.createQuery("select c from Customer c").list();

注意: HQL查询非常类似于标准的SQL查询,当查询数据表中所有的记录时
      可以省略select关键字,from不区分大小写但是Customer时类名区分大小写
      还可以给类名设置别名

排序查询

排序查询和SQL语句中的排序的语法是一样的
    * 升序
        * session.createQuery("from Customer order by cust_id").list();
    * 降序
        * session.createQuery("from Customer order by cust_id desc").list();

String hql = "select * from order by sal desc,emptno asc"       

分页查询

* Hibernate框架提供了分页的方法,咱们可以调用方法来完成分页
    * 两个方法如下
        * setFirstResult(a)  -- 从哪条记录开始,如果查询是从第一条开启,值是0
           (当前页-1)*pageSize
        * setMaxResults(b)   -- 每页查询的记录条数

    * 演示代码如下
        * List<LinkMan> list = session.createQuery("from LinkMan").setFirstResult(0).setMaxResults().list();

条件查询

/* setParameter("?号的位置,默认从0开始","参数的值"); 不用考虑参数的具体类型
* 按位置绑定参数的条件查询(指定下标值,默认从0开始)
* 按名称绑定参数的条件查询(HQL语句中的 ? 号换成 :名称 的方式)
* 例如代码如下
    Query query = session.createQuery("from Linkman where lkm_name like ? order by lkm_id desc");
    <!--设置分页-->
    query.setFirstResult(0).setMaxResults(3);
    query.setParameter(0, "%熊%");
    List<Linkman> list = query.list();
    for (Linkman linkman : list) {
        System.out.println(linkman);
}
* 还能够起别名
    String hql2 = " from  cn.itcast.domain.Customer where cust_id = :id ";
    query.setParameter("id", 2l);

聚合查询

@Test
//统计查询
//count计数
//sum 求和
//avg平均数
//max
//min
public void fun5(){
    Session session = HibernateUtils.openSession();
    Transaction tx = session.beginTransaction();
    //----------------------------------------------------
    String hql1 = " select count(*) from  cn.itcast.domain.Customer  ";//完整写法
    String hql2 = " select sum(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql3 = " select avg(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql4 = " select max(cust_id) from  cn.itcast.domain.Customer  ";//完整写法
    String hql5 = " select min(cust_id) from  cn.itcast.domain.Customer  ";//完整写法

    Query query = session.createQuery(hql5);

    Number number  = (Number) query.uniqueResult();

    System.out.println(number);
    //----------------------------------------------------
    tx.commit();
    session.close();

}

HQL的投影查询

1. 投影查询就是想查询某一字段的值或者某几个字段的值(不是所有字段)
2. 投影查询的案例
    * 如果查询多个字段,例如下面这种方式
        String hql = "select c.cust_name,c.cust_level from Customer c"
        List<Object[]> list = session.createQuery(hql).list();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }

    * 如果查询两个字段,也可以把这两个字段封装到对象中
        * 先在持久化类中提供对应字段的构造方法
        * 使用下面这种HQL语句的方式
            List<Customer> list = session.createQuery("select new Customer(c.cust_name,c.cust_level) from Customer c").list();
            for (Customer customer : list) {
                System.out.println(customer);
            }

HQL多表查询(不常用)

原生SQL(回顾)
<!--SQL99规范-->
* 交叉连接
    * 产生笛卡尔积
    * select * from1 corss join2
* 自然连接
    * 表中所有同名列默认作为连接条件
    * select * from1 natural join2
* using 子句连接
    * 可以显示指定某同名列作为连接条件
    * select * from1 join2 using(name)
* on子句连接(内连接)
    * 每一个on子句指定一个连接条件
    * select * from1 (inner) join2 on 
* 外连接
    * 内连接会丢失信息,想要不丢失信息使用外连接
    * 左外连接
    * 右外连接
    * 全外连接
HQL连接查询

hibernate进行多表查询的方式跟SQL其实很像,在原来的基础上又多出来了一些操作
- 交叉连接
- 内连接
- 普通内连接
- 迫切内连接
- 外连接
- 左外连接
- 迫切左外连接
- 右外连接

    @Test
    //HQL 内连接 => 将连接的两端对象分别返回.放到数组中.
    //不用写具体的on条件,直接写关联属性即可
    // 返回的是一个 list<Object[]>
    public void fun1(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c inner join c.linkMens ";

        Query query = session.createQuery(hql);

        List<Object[]> list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();

    }

    @Test
    //HQL 迫切内连接 => 帮我们进行封装.返回值就是一个对象
    //在join后面添加 fetch 关键字
    //底层执行的sql语句跟 内连接是一样的
    // 迫切内连接查询得到的对象会有重复的用 distinct的话又会降低数据
    //库性能只能自己写一个方法去重了
    public void fun2(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c inner join fetch c.linkMens ";

        Query query = session.createQuery(hql);

        List<Customer> list = query.list();

        System.out.println(list);
        //----------------------------------------------------
        tx.commit();
        session.close();

    }

    @Test
    //HQL 左外连接 => 将连接的两端对象分别返回.放到数组中.
    public void fun3(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c left join c.linkMens ";

        Query query = session.createQuery(hql);

        List<Object[]> list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();

    }


    @Test
    //HQL 右外连接 => 将连接的两端对象分别返回.放到数组中.
    public void fun4(){
        Session session = HibernateUtils.openSession();
        Transaction tx = session.beginTransaction();
        //----------------------------------------------------
        String hql = " from Customer c right join c.linkMens ";

        Query query = session.createQuery(hql);

        List<Object[]> list = query.list();

        for(Object[] arr : list){
            System.out.println(Arrays.toString(arr));
        }
        //----------------------------------------------------
        tx.commit();
        session.close();

    }

QBC

0. QBC:Query By Criteria  按条件进行查询

1. 简单查询,使用的是Criteria接口 查询全部
    List<Customer> list = session.createCriteria(Customer.class).list();
    for (Customer customer : list) {
        System.out.println(customer);
    }

2. 排序查询
    * 需要使用addOrder()的方法来设置参数,参数使用org.hibernate.criterion.Order对象
    * 具体代码如下:
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Criteria criteria = session.createCriteria(Linkman.class);
        // 设置排序
        criteria.addOrder(Order.desc("lkm_id"));
        List<Linkman> list = criteria.list();
        for (Linkman linkman : list) {
            System.out.println(linkman);
        }
        tr.commit();

3. 分页查询
    * QBC的分页查询也是使用两个方法
        * setFirstResult();
        * setMaxResults();

    * 代码如下;
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Criteria criteria = session.createCriteria(Linkman.class);
        // 设置排序
        criteria.addOrder(Order.desc("lkm_id"));
        criteria.setFirstResult(0);
        criteria.setMaxResults(3);
        List<Linkman> list = criteria.list();
        for (Linkman linkman : list) {
            System.out.println(linkman);
        }
        tr.commit();

4. 条件查询(Criterion是查询条件的接口,Restrictions类是Hibernate框架提供的工具类,使用该工具类来设置查询条件)
    * 条件查询使用Criteria接口的add方法,用来传入条件。
    * 使用Restrictions的添加条件的方法,来添加条件,例如:
        * Restrictions.eq           -- 相等
        * Restrictions.gt           -- 大于号
        * Restrictions.ge           -- 大于等于
        * Restrictions.lt           -- 小于
        * Restrictions.le           -- 小于等于
        * Restrictions.between      -- 在之间
        * Restrictions.like         -- 模糊查询
        * Restrictions.in           -- 范围
        * Restrictions.and          -- 并且
        * Restrictions.or           -- 或者

    * 测试代码如下
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Criteria criteria = session.createCriteria(Linkman.class);
        // 设置排序
        criteria.addOrder(Order.desc("lkm_id"));
        // 设置查询条件
        criteria.add(Restrictions.or(Restrictions.eq("lkm_gender", "男"), Restrictions.gt("lkm_id", 3L)));
        List<Linkman> list = criteria.list();
        for (Linkman linkman : list) {
            System.out.println(linkman);
        }
        tr.commit();

5. 聚合函数查询(Projection的聚合函数的接口,而Projections是Hibernate提供的工具类,使用该工具类设置聚合函数查询)
    * 使用QBC的聚合函数查询,需要使用criteria.setProjection()方法
    * 具体的代码如下
        Session session = HibernateUtils.getCurrentSession();
        Transaction tr = session.beginTransaction();
        Criteria criteria = session.createCriteria(Linkman.class);
        criteria.setProjection(Projections.rowCount());
        List<Number> list = criteria.list();
        Long count = list.get(0).longValue();
        System.out.println(count);
        tr.commit();

离线查询条件

image
image
- web层或者service层

DetachedCriteria dc  = DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致)
//将dc传到dao层    
  • dao层
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Criteria c = dc.getExecutableCriteria(session);
List list = c.list();

原生SQL

1. 基本语法
    Session session = HibernateUtils.getCurrentSession();
    Transaction tr = session.beginTransaction();

    SQLQuery sqlQuery = session.createSQLQuery("select * from cst_linkman where lkm_gender = ?");
    sqlQuery.setParameter(0,"男");
    sqlQuery.addEntity(Linkman.class);
    List<Linkman> list = sqlQuery.list();
    System.out.println(list);
    tr.commit();

查询优化(看文档比较好)

hibernate本身的查询效率不是很好,尤其是在获取关联对象的时候,那么我们需要对一些查询语句进行一些优化操作

hibernate的抓取策略

概述

 抓取策略是当应用程序需要在关联关系间进行导航的时候,hibernate如何获取关联对象的策略
 hibernate的抓取策略是提升性能的一种手段,可以在获取关联对象的时候,对发送的sql语句进行优化,但是抓取策略需要和延迟加载一起使用来提升性能

延迟加载分类

 所谓的延迟加载就是当真正需要数据的时候,才真正执行数据加载的操作(发送sql语句),
- 延迟加载的分类
- 类级别延迟加载
- 查询某个对象的时候是否有延迟
- 通常在标签上配置
- 关联级别的延迟加载
- 查询一个对象的关联对象的时候是否采用延迟加载
- 通常在或者上配置

  • 类级别延迟加载策略
* get方法: 没有任何策略.调用即立即查询数据库加载数据.
* load方法: 应用类级别的加载策略,默认延迟加载,当使用load方法查询时不会马上发送
            sql语句,只有用数据的时候才会加载


* 详解: 延迟加载的原理:采用cglib代理技术对加载的对象进行加强,只有当
       用到该对象的时候才会发送sql语句
  • 关联级别查询加载策略

这里太多了,总结一句话,用默认的就对了

扩大Session的作用范围

image

猜你喜欢

转载自blog.csdn.net/qq_36974281/article/details/81407561
今日推荐