Hibernate入门(四)—— 查询

一、Hibernate查询

1.Hibernate检索(查询)方式的分类

  • OID检索 :根据主键查询,get/load

  • 对象导航检索 :通过一个对象获得其关联对象.【重点】

    Category category = session.get(Category.class, 1);
    Set<Product> products = category.getProducts();
  • HQL检索 :HQL,Hibernate Query Language(Hibernate查询语言,语法与SQL类似,但是又是面向对象的 ) 【掌握】

  • QBC检索 :QBC,Query By Criteria(条件查询,更加面向对象的查询方式) 【掌握】

  • SQL检索 :SQL,使用原生SQL进行查询 【了解】

2.HQL查询

2.1概述

​   HQL:Hibernate Query Language。 是面向对象(在sql里面的列名在hql里面应该写属性名)的查询语言, 它和SQL查询语言有些相似。

​ 语法: 

String hql =...

Query query = session.createQuery(hql);

  • list(); 查询多个

  • uniqueResult();查询一个

    原则: 把表名改成类名, 把数据库的列改成Java里面的属性名

2.2基本查询
2.2.1查询所有
  • 查询所有的分类

     1 //查询所有的分类
     2     @Test
     3     public void fun01(){
     4         Session session = HibernateUtils.openSession();
     5         Transaction transaction = session.beginTransaction();
     6         
     7         //String hql = "select c from Category c";
     8         String hql = "from Category";
     9         Query query = session.createQuery(hql);
    10         List<Category> list = query.list();
    11         for (Category category : list) {
    12             System.out.println(category.toString());
    13         }
    14         
    15         transaction.commit();
    16         session.close();
    17     }
2.2.2条件查询
  • 大于,小于,大于等于,大于小于查询

     1 //查询id大于1的分类
     2     @Test
     3     public void fun02(){
     4         Session session = HibernateUtils.openSession();
     5         Transaction transaction = session.beginTransaction();
     6         
     7         /*String hql = "from Category where cid > ?";
     8         Query query = session.createQuery(hql);
     9         query.setInteger(0, 1);*/
    10         
    11         String hql = "from Category where cid > :类别id";
    12         Query query = session.createQuery(hql);
    13         query.setInteger("类别id", 1);
    14         List<Category> list = query.list();
    15         for (Category category : list) {
    16             System.out.println(category.toString());
    17         }
    18         
    19         transaction.commit();
    20         session.close();
    21     }
  • like查询

     1 //查询商品名包含iPhone的商品
     2     @Test
     3     public void fun03(){
     4         Session session = HibernateUtils.openSession();
     5         Transaction transaction = session.beginTransaction();
     6         
     7         
     8         String hql = "from Product where pname like ?";
     9         Query query = session.createQuery(hql);
    10         query.setString(0, "%iPhone%");
    11         List<Product> list = query.list();
    12         for (Product product: list) {
    13             System.out.println(product.toString());
    14         }
    15         
    16         transaction.commit();
    17         session.close();
    18     }
  • between and查询

    String hql = "from Product where price between ? and ?";
    Query query = session.createQuery(hql);
    query.setDouble(0, 2000);
    query.setDouble(1, 5000);
    List<Product> list = query.list();
  • in 查询

     1 @Test
     2      //查询pid在(2,8,11,12,100)的商品信息
     3      public void fun05(){
     4          Session session = HibernateUtils.getCurrentSession();
     5          Transaction transaction = session.beginTransaction();
     6          
     7         //String sql = "select * from t_product where  pid in(?,?,?,?)";
     8          String hql = "from Product where pid in(?,?,?,?)";
     9          Query query = session.createQuery(hql);
    10          //设置参数,查询
    11          List list = query.setInteger(0, 2).setInteger(1, 8).setInteger(2, 11).setInteger(3, 12).list();
    12          
    13          System.out.println(list.toString());
    14          
    15          transaction.commit();
    16 17      }
2.3.聚合查询
  • 统计类别的个数

    String hql = "select count(*) from Category";
    Query query = session.createQuery(hql);
    Long n =  (Long) query.uniqueResult();
    System.out.println(n.intValue());
2.4分组查询
  • 统计各个类别的商品数量

    String hql = "select category.cid, count(*) from Product group by category.cid";
    Query query = session.createQuery(hql);
    List<Object[]> list = query.list();
    for (Object[] objects : list) {
        System.out.println(Arrays.toString(objects));
    }
2.5排序查询
  • 安照商品价格(升序)查询所有的商品

    String hql = "from Product order by price asc";
    Query query = session.createQuery(hql);
    List<Product> list = query.list();
    for (Product product : list) {
        System.out.println(product);
    }
2.6.分页查询

​ setFirstResult:设置开始查询的下标,最小取值是0,0代表第一条记录

​ setMaxResults: 设置查询结果显示的条数。

  • 显示第一页的数据,一页显示4条

    String hql = "from Product";
    Query query = session.createQuery(hql);
    query.setFirstResult(0);
    query.setMaxResults(4);
    List<Product> list = query.list();
    for (Product product : list) {
            System.out.println(product);
    }
2.7 投影查询

​ 查询指定字段

  • 查询商品的名字和价格

    String hql = "select pname, price from Product";
    Query query = session.createQuery(hql);
    List<Object[]> list =  query.list();
    for (Object[] objects : list) {
        System.out.println(Arrays.toString(objects));
    }

3.QBC查询

3.1概述

​   QBC,Query By Criteria(条件查询,更加面向对象的查询方式)

3.2常见的条件查询
  • 语法

    //创建QBC条件查询
    Criteria criteria = session.createCriteria(Class);
    //添加条件
    criteria.add(Restrictions.api...);
    //查询多个
    List list = criteria.list();
    //或者查询一个
    Object object =  criteria.uniqueResult();
运算符条件API描述
= Restrictions.eq() 等于
> Restrictions.gt() 大于
< Restrictions.lt() 小于
>= Restrictions.ge() 大于等于
<= Restrictions.le() 小于等于
between Restrictions.between() 在某个范围内
like Restrictions.like() 模糊查询
in Restrictions.in() 在...中
and Restrictions.and() 并且
or Restrictions.or() 或者
  • Java代码

     1 // 条件查询
     2     @Test
     3     public void fun01() {
     4         Session session = HibernateUtils.openSession();
     5         Transaction transaction = session.beginTransaction();
     6  7         Criteria criteria = session.createCriteria(Product.class);
     8         List<Product> list = criteria.add(Restrictions.between("price", 2000.0, 3000.0)).list();
     9         for (Product product : list) {
    10             System.out.println(product.toString());
    11         }
    12         
    13         transaction.commit();
    14         session.close();
    15     }
    //and 查询; 查询商品名以iP开头的并且价格大于4000的商品
    Criteria criteria = session.createCriteria(Product.class);
    List<Product> list = criteria.add(Restrictions.like("pname", "iP%")).add(Restrictions.gt("price", 4000.0)).list();
    //or查询;  查询价格大于3000的或者pid=1的商品
    Criteria criteria = session.createCriteria(Product.class);
    List<Product> list = criteria.add(Restrictions.or(Restrictions.gt("price", 3000.0)).add(Restrictions.eq("pid", 1))).list();
3.3.聚合查询
  • 语法

    //创建QBC条件查询
    Criteria criteria = session.createCriteria(Class);
    //设置聚合
    criteria.setProjection(Projections.api...);
    //查询出结果
    long result = (long) criteria.uniqueResult();
    运算符条件API描述
    sum Projections.sum() 求和
    count Projections.count() 计数
    max Projections.max() 最大值
    min Projections.min() 最小值
    avg Projections.avg() 平均值
  • 统计商品的数量

    Criteria criteria = session.createCriteria(Product.class);
    Object result = criteria.setProjection(Projections.count("pid")).uniqueResult();
    System.out.println("result="+result);
  • 多项聚合

  • //创建QBC条件查询
    Criteria criteria = session.createCriteria(Class);
    //添加多种聚合
    ProjectionList list = Projections.projectionList();
    list.add(Projections.api...);
    ...
    //设置聚合
    criteria.setProjection(list);
    //查询出结果
    Object[] result = (Object[]) criteria.uniqueResult();
    
    //实例
    //统计每一个类别下的商品数量  cid count(pid)  两个聚合条件
    Criteria criteria = session.createCriteria(Product.class);
    ProjectionList projectionList = Projections.projectionList();   
    projectionList.add(Projections.groupProperty("category.cid")); projectionList.add(Projections.count("pid")); List<Object[] > list = criteria.setProjection(projectionList).list();
3.4分组查询
  • 统计不同类别下商品的数量

    Criteria criteria = session.createCriteria(Product.class);
    ProjectionList projectionList = Projections.projectionList();
    projectionList.add(Projections.count("pid")).add(Projections.groupProperty("category.cid"));
    ​
    List<Object[]> list = criteria.setProjection(projectionList).list();
    for (Object[] objects : list) {
        System.out.println(Arrays.toString(objects));
    }
3.5排序查询
  • 语法

    //创建QBC条件查询
    Criteria criteria = session.createCriteria(Class);
    //添加排序
    criteria.addOrder(Order.api...);
    //查询出结果
    List list = criteria.list();
    运算符条件API描述
    desc Order.desc() 降序
    asc Order.asc() 升序
3.6.分页查询

​ setFirstResult:设置开始查询的下标,最小取值是0,0代表第一条记录 设置a

​ setMaxResults: 设置查询结果显示的条数。 设置 b

3.7离线条件查询

​   我们之前也执行过条件查询,不过这些条件查询都是先创建了Criteria对象,然后再不断的追加条件。这种情况在提交比较少的时候,看上去是还不错的。 假如我们这些参数都是要上层service 传递过来的,那么显得就不是那么好看了。所以我们想想能否在外面先封装好了,然后直接给我一个总的条件即可。 这个总的条件,就是包含了前面的所有的条件。这就是离线条件查询。 意思是,可以现在前面先封装条件, 脱离session 创建出Criteria这个情况。

  • 语法

    //创建离线的DetachedCriteria对象
    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(User.class);
    //设置条件
    detachedCriteria.add(Restrictions.like("u_name", "%奥%"));
    //转成可执行状态
    Criteria criteria = detachedCriteria.getExecutableCriteria(session);
    
    List<User> list = criteria.list();

4,SQL查询【了解】

  • Eg

    String sql = "select * from t_product";
    SQLQuery sqlQuery = session.createSQLQuery(sql);
    sqlQuery.addEntity(Product.class);
    ​
    List<Product> list = sqlQuery.list();
            
    for (Product product : list) {
        System.out.println(product.toString());
    }

5.连接查询

5.1MySql里面的多表查询
5.1.1交叉查询
  • 语法

    select * from A,B
5.1.2内连接查询
  • 隐式内连接查询

     select * from A ,B where A.id = B.id;
  • 显示内连接

    select * from A inner join B on A.id = B.id;
5.1.3外连接查询
  • 左外连接

     select * from A left outer join B on A.id = B.id;
  • 右外连接

     select * from A right outer join B on A.id = B.id;
5.2 HQL连接查询
5.2.1类别
  • 交叉连接

  • 内连接:内连接、迫切内连接

  • 外连接:​左外连接、右外连接

    连接类型语法
    内连接 inner join 或者 join
    迫切内连接 inner join fetch 或者 join fetch
    左外连接 left outer join 或者 left join
    迫切左外连接 left outer join fetch 或者 left join fetch
    右外连接 right outer join 或者 right join
    迫切右外连接 right outer join fetch 或者 right join fetch
5.2.2内连接

​ 内连接查询可以获取两表的公共部分的记录。

  • HQL内连接(发送三条查询语句)

    String hql = "from Category c inner join c.products";
    Query query = session.createQuery(hql);
    List<Object[]> list =  query.list();
  • HQL迫切内连接(发送一条查询语句)

    //String hql = "from Category c inner  join fetch c.products";
    String hql = "select distinct c  from Category c inner  join fetch c.products";
    Query query = session.createQuery(hql);
    List<Category> list =  query.list();
5.2.3外连接
  • HQL左外连接

    String hql = "from Category c left outer join  c.products";
    List<Object[]> list = session.createQuery(hql).list();
  • HQL迫切左外连接

    String hql = "from Category c left outer  join fetch c.products";
    List<Category> list = session.createQuery(hql).list();

  总结:

    • ​ 迫切连接是Hibernate独有的查询方式,迫切内连接比内连接多一个关键字fetch
    • ​ 内连接查询结果中为Object[]数组
    • ​ 迫切内连接查询结果为具体对象

二、查询优化

1、类级别延迟加载

1.1 描述

​ 懒加载默认是开启的.一般不需要修改

​ session.get(): 非懒加载方法

​ session.load(): 默认就是是懒加载

1.2使load懒加载失效

​  在映射配置文件的<class>标签上配置lazy=”false” 

<class name="com.pri.bean.Category" table="t_category" lazy="false">

2.关联级别的懒加载

2.1 概述

​   当查询对应的对象时候, 是否立即查询出其关联的对象; eg: 查询id的为1分类,是否立即查询出是该类别下的商品

​   一般通过 '抓取策略' 和 '懒加载' 配合起来优化查询.抓取策略:意思是抓取其关联对象,在<set><many-to-one>标签上有一个fetch属性,fetch控制发送什么类型的语句来抓取其关联的对象

​   fetch: 抓取策略 :控制发送什么类型的Sql语句 sql语句:就是对表查询(连接)

​   lazy: 懒或者不懒

2.2set的懒加载
2.2.1描述

在一的一方操作,即在set标签上配置 fetch 和 lazy

  • fetch:控制的是查询其关联对象的时候采用的SQL语句的格式.

    fetch的取值发送的SQL语句类型
    select:默认值 发送一条select语句查询其关联对象.
    join 发送一条迫切左外连接查询关联对象.
    subselect 发送一条子查询查询其关联对象.
  • lazy:控制的是查询其关联对象的时候是否采用延迟加载的策略.

    lazy的取值含义
    true(默认值) 默认查询关联对象的时候采用延迟加载.
    false 查询关联对象的时候 不采用延迟加载
    extra 及其懒惰. 查询关联对象的时候 采用比延迟加载更懒惰的方式进行查询.
2.2.2例子

​ 下面的操作都是在在一的一方操作,即在set标签上配置 fetch 和 lazy

  • 当fetch取值为select的时候

    fetch的取值lazy的取值结果
    select true 多方在使用时才进行加载(懒加载) 注: 默认值
    select false 多方在一方加载时就加载(不是懒加载)
    select extra 多方在使用时才进行加载,如果使用时的操作是聚合类型,那么只会进行聚合查询。
  • 当fetch取值为join的时候

    fetch的取值lazy的取值结果
    join lazy失效(不管是true还是false) fetch采用的是迫切左外连接查询,将两张表的结果全部查询出来。lazy失效。
  • 当fetch取值为subselect的时候

    fetch的取值lazy的取值结果
    subselect true 多方在使用时才进行加载,发送的是子查询语句
    subselect false 多方在一方加载时就加载,发送的是子查询语句
    subselect extra 多方在一方加载时就加载,如果使用时的操作是聚合类型,那么只会进行聚合查询发送的是子查询语句

    注意: 使用Hibernate子查询时候,不能查一个. Hibernate如果发现in() 的值是一个,把in变成=

2.3many-to-one懒加载
2.3.1描述

在多的一方操作,即在many-to-one标签上配置 fetch 和 lazy

  • fetch:控制的是查询其关联对象的时候采用的SQL语句的格式.

    fetch的取值发送的SQL语句类型
    select:默认值 发送一条select语句查询其关联对象.
    join 发送一条迫切左外连接查询关联对象.
  • lazy:查询其关联对象的时候是否采用延迟加载.

    lazy的取值含义
    proxy 默认值.是否采用延迟 取决于 一的一方的class上的lazy的值.
    false 不采用延迟加载其关联对象.
    no-proxy(了解) 不用研究是否采用延迟
2.3.2例子

​ 下面的操作都是在多的一方操作,即在many-to-one标签上配置 fetch 和 lazy

  • 当select为fetch的时候,发送的是普通的sql语句

    fetch的取值lazy的取值结果
    select proxy 如果一的一方的class上的lazy的值为true,使用一的一方再加载(懒加载); 如果一的一方的class上的lazy的值为false,一方在多方加载时就加载(不是懒加载)
    select false 一方在多方加载时就加载(不是懒加载)
  • 当select为join的时候,是迫切左外连接

    fetch的取值lazy的取值结果
    join 失效 发送左外连接查询,不是懒加载

3 批量抓取(了解)

  • 在set标签上配置 batch-size = num

    1 Criteria criteria = session.createCriteria(Category.class);
    2 List<Category> list = criteria.list();
    3 4 for (Category category : list) {
    5     Set<Product> products = category.getProducts();
    6     for (Product product : products) {
    7         System.out.println(product.toString());
    8     }
    9 }

同时抓取多方表中指定的条数的数据


原文地址:https://www.cnblogs.com/gdwkong/p/8342905.html