Hibernate详解4(查询方式和抓取策略)

Hibernate的查询方式

OID查询

利用对象的ID进行检索

  1. 使用get() 方法

Customer customer = session.get(Customer.class,1l);

  1. 使用load() 方法

Customer customer = session.load(Customer.class,1l);

对象导航检索查询

Hibernate根据已经查询出来的对象,获得其关联对象的一种查询方式。

Customer customer = session.get(Customer.class, 5l);
Set linkMans = customer.getLinkMans();

HQL检索查询

是一种面向对象化的查询语言,语法类似于SQL,通过session.createQuery(),接受一个HQL进行查询。

HQL的查询 查询的是对象 :from Customer,
如果使用条件查询,from Customer where cust_id = ? ,cust_id是用的对象中的属性	

简单查询

  @Test
    /**
     * HQL的简单查询
     */
    public void demo2() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        // 简单的查询
        Query query = session.createQuery("from Customer");
        List<Customer> list = query.list();

        // sql中支持*号的写法:select * from cst_customer; 但是在HQL中不支持*号的写法。
        /*
         * Query query = session.createQuery("select * from Customer");// 报错
         * List<Customer> list = query.list();
         */

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

别名查询

  @Test
    /**
     * 别名查询
     */
    public void demo3() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        // 别名的查询
        /*
         * Query query = session.createQuery("from Customer c"); List<Customer>
         * list = query.list();
         */

        Query query = session.createQuery("select c from Customer c");
        List<Customer> list = query.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

条件查询

注意:设置条件时候,从 0 开始:query.setParameter(0,“aa”);

@Test
    /**
     * 条件查询
     */
    public void demo5() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        // 条件的查询
        // 一、按位置绑定:根据参数的位置进行绑定。
        // 一个条件
        /*
         * Query query = session.createQuery("from Customer where cust_name = ?");
         * query.setParameter(0, "李兵");  是从0 开始的,PreporeStatement 中是以 1 开始的
         * List<Customer> list = query.list();
         */

        // 多个条件
        /*
         * Query query = session.createQuery(
         * "from Customer where cust_source = ? and cust_name like ?");
         * query.setParameter(0, "小广告"); query.setParameter(1, "李%");
         * List<Customer> list = query.list();
         */

        // 二、按名称绑定
        Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
        // 设置参数:
        query.setParameter("aaa", "朋友推荐");
        query.setParameter("bbb", "李%");
        List<Customer> list = query.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

投影查询

 @Test
    /**
     * 投影查询
     */
    public void demo6() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 投影查询
        // 单个属性
        /*
         * List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
         * for (Object object : list) {
         *      System.out.println(object);
         *  }
         */

        // 多个属性:
        /*
         * List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
         * for(Object[] objects : list) {
         *      System.out.println(Arrays.toString(objects));
          *   }
         */

        // 查询多个属性,但是我想封装到对象中。
        List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

排序查询

@Test
    /**
     * 排序查询
     */
    public void demo4() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        // 排序的查询
        // 默认情况
        // List<Customer> list = session.createQuery("from Customer order bycust_id").list();
        // 设置降序排序 升序使用asc 降序使用desc
        List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

分页查询

@Test
    /**
     * 分页查询
     */
    public void demo7() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 分页查询
        Query query = session.createQuery("from LinkMans");
        query.setFirstResult(5); //开始的位置
        query.setMaxResults(5);  //一页查询几个
        List<LinkMans> list = query.list();

        for (LinkMans LinkMans : list) {
            System.out.println(LinkMans);
        }
        tx.commit();
    }

分组统计查询

 @Test
    /**
     * 分组统计查询
     */
    public void demo8() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 聚合函数的使用:count(),max(),min(),avg(),sum()
        Object object = session.createQuery("select count(*) from Customer").uniqueResult();
        System.out.println(object);
        // 分组统计:
        List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source").list();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
        tx.commit();
    }

HQL的多表查询

SQL的多表查询

  • 连接查询

    • 交叉连接 :笛卡尔积
    • 内连接
      • 隐式内连接 :select * from A,B where A.id = B.id
      • 显示内连接 : select * from A inner join B on A.id=B.id
    • 外链接
      • 左外连接:select * from A left (outer) join B on A.id=B.id
      • 右外连接:select * from A right (outer) join B on A.id = B.id
  • 子查询 …

HQL的多表查询

  • 连接查询
    • 交叉连接 :笛卡尔积
    • 内连接
      • 隐式内连接 :select * from A,B where A.id = B.id
      • 显示内连接 : select * from A inner join B on A.id=B.id
      • 迫切内连接
    • 外链接
      • 左外连接:select * from A left (outer) join B on A.id=B.id
      • 右外连接:select * from A right (outer) join B on A.id = B.id
      • 迫切左外连接
@Test
    /**
     * HQL的多表查询
     */
    public void demo9() {
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();
        // SQL:SELECT * FROM cst_customer c INNER JOIN cst_LinkMans l ON
        // c.cust_id = l.lkm_cust_id;
        // HQL:内连接 from Customer c inner join c.LinkManss
        /*
         * List<Object[]> list = session.createQuery(
         * "from Customer c inner join c.LinkManss").list(); for (Object[]
         * objects : list) { System.out.println(Arrays.toString(objects)); }
         */

        // HQL:迫切内连接 其实就在普通的内连接inner join后添加一个关键字fetch. from Customer c inner
        // join fetch c.LinkManss
        List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.LinkManss")
                .list();// 通知hibernate,将另一个对象的数据封装到该对象中

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

QBC检索查询

QBC查询:Query By Criteria,条件查询。是一种更加面向对象化的查询的方式。

简单查询

@Test
    /**
     * 简单的查询
     */
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 获得Criteria的对象
        Criteria criteria = session.createCriteria(Customer.class);
        List<Customer> list = criteria.list();

        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

条件查询

加条件的时候默认的是and连接,如果想使用or ,这样写:criteria.add(Restrictions.or(Restrictions.like(“cust_name”, “李%”)));
每添加一个条件,就是加一个and 拼接上条件

 
@Test
    /**
     * 条件查询
     */
    public void demo4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 条件查询
        Criteria criteria = session.createCriteria(Customer.class);
        // 设置条件:
        /**
         * =   eq
         * >   gt
         * >=  ge
         * <   lt
         * <=  le
         * <>  ne
         * like
         * in
         * and
         * or
         */
        //使用or
        criteria.add(Restrictions.or(Restrictions.eq("cust_source","制药"),Restrictions.eq("cust_source", "产品")));

        //默认使用and
        criteria.add(Restrictions.eq("cust_source", "产品"));
        criteria.add(Restrictions.or(Restrictions.like("cust_name", "张%")));
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        tx.commit();
    }

分页查询

@Test
    /**
     * 分页查询
     */
    public void demo3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 分页查询
        Criteria criteria = session.createCriteria(LinkMans.class);
        criteria.setFirstResult(10);
        criteria.setMaxResults(10);
        List<LinkMans> list = criteria.list();

        for (LinkMans LinkMans : list) {
            System.out.println(LinkMans);
        }
        tx.commit();
    }

统计查询

add :普通的条件。where后面条件
addOrder :排序
setProjection :聚合函数 和 group by having

@Test
    /**
     * 统计查询
     */
    public void demo5(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        Criteria criteria = session.createCriteria(Customer.class);
        /**
         * add				:普通的条件。where后面条件
         * addOrder			:排序
         * setProjection	:聚合函数 和 group by having
         */
        criteria.setProjection(Projections.rowCount());
        Long num = (Long) criteria.uniqueResult();
        System.out.println(num);
        tx.commit();
    }

离线条件查询

用于当多个条件进行判断的时候,如果条件非常多,就可以使用离线查询,这是脱离session使用
在这里插入图片描述

 @Test
    /**
     * 离线条件查询
     */
    public void demo6(){
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
        detachedCriteria.add(Restrictions.like("cust_name", "李%"));

        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Criteria criteria = detachedCriteria.getExecutableCriteria(session);
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
        transaction.commit();
    }

SQL检索查询

@Test
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		/*SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
		List<Object[]> list = sqlQuery.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}*/
		
		SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
		//添加实体,将查询出来的数据封装到实体中去
		sqlQuery.addEntity(Customer.class);
		List<Customer> list = sqlQuery.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

Hibernate的抓取策略

延迟加载的概述

什么是延迟加载

延迟加载:lazy(懒加载),就是当查询到该行代码的时候,不会立即执行SQL语句,而是当用到该对象属性的时候,才会发送SQL语句进行查询。
例如:Customer cus = session.load(Customer.class,1l); ,当执行到这行代码的时候,不会立即发送sql语句,而是当使用他的时候 customer.getCust_name();才会发送sql语句。
使用customer.getCust_name();则不会发送sql语句,因为id是已知的。

延迟加载的分类

  • 类级别的延迟加载
    • 指的是使用load()方法查询某个对象的时候,是否采用延迟加载, session.load(Customer.class,1l);
    • 类级别的延迟加载使用<class>标签上的lazy属性进行配置的,lazy默认值为true,如何使lazy失效
      • 将lazy的值改为false
      • 将持久化类用final修饰
      • Hibernate.Initialize()
  • 关联级别的延迟加载
    • 关联级别的加载:当查询出一个对象的时候,通过该对象去查询其关联对象,是否采用延迟加载

    • Customer customer = session.get(Customer.class,1l);
      customer.getLinkMans();----通过客户获得联系人的时候,联系人对象是否采用了延迟加载,称为是关联级别的延迟。

        关联级别的加载往往和抓取策略一起使用,优化语句
      

抓取策略

抓取策略的概述

通过一个对象获得其关联对象在抓取的时候需要发送SQL语句,采用什么样格式的SQL语?SQL语句如何发送?

  1. 通过set标签或者many-to-one标签上的fetchsh属性的值进行设置
    fetch属性作用是发送什么格式的sql语句,而lazy属性的作用是什么时候发送sql语句
  2. fetch和这些标签上的lazy如何设置优化发送的SQL语句???

set标签上的fetch和lazy的使用

查询到一的一方的对象,去关联查询多的一方的对象

  • fetch:抓取策略,控制SQL语句的格式
    • select:默认值,发送正常形式的sql语句,查询关联对象
    • join:发送采取 迫切左外连接形式的sql语句,查询关联对象
    • subselect:发送采取子查询形式的sql语句,查询关联对象
  • lazy:延迟加载,控制查询其关联对象的时候,是否采用延迟加载(SQL语句什么时候进行发送)。
    • true:默认值,查询关联对象的时候,采用延迟加载
    • false:查询关联对象的时候,不采用延迟加载
    • extra:及其懒惰加载(与延迟加载发送的sql语句不一样)

在实际开发中,一般都采用默认值。如果有特殊要求,采用join

fetch:select --------------------- lazy:true
fetch:select --------------------- lazy:false
fetch:select --------------------- lazy:extra
fetch:join --------------------- lazy:失效,在查询客户的时候,采用左外连接,直接就把联系人查出来了
fetch:subselect--------------------- lazy:true
fetch:subselect--------------------- lazy:false
fetch:subselect--------------------- lazy:extra

代码实现

package com.day04;

import com.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import java.util.List;

/**
 * 在<set>上的fetch和lazy
 * 根据客户查询客户的联系人,在一 的一方(客户)的<set> 标签上设置
 */
public class HibernateDemo5 {

    @Test
    /**
     * 默认情况:
     */
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 查询5号客户
        Customer customer = session.get(Customer.class, 5l);// 发送一条查询客户的SQL
        System.out.println(customer.getCust_name());
        // 查看1号客户的每个联系人的信息
        for (LinkMans LinkMans : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
            System.out.println(LinkMans.getLkm_name());
        }
        tx.commit();
    }

    @Test
    /**
     * 设置fetch="select" lazy="true"
     */
    public void demo2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 查询1号客户
        Customer customer = session.get(Customer.class, 5l);// 发送一条查询客户的SQL
        System.out.println(customer.getCust_name());
        // 查看1号客户的每个联系人的信息
        for (LinkMans LinkMans : customer.getLinkMans()) {// 发送一条根据客户ID查询联系人的SQL
            System.out.println(LinkMans.getLkm_name());
        }
        tx.commit();
    }

    @Test
    /**
     * 设置	fetch="select" lazy="false"
     */
    public void demo3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 查询5号客户
        Customer customer = session.get(Customer.class, 5l);// 发送两条SQL语句:查询客户的名称,查询客户关联联系人
        System.out.println(customer.getCust_name());
		// 查看1号客户的每个联系人的信息
//		for (LinkMans LinkMans : customer.getLinkMans()) {//
//			System.out.println(LinkMans.getLkm_name());
//		}

        System.out.println(customer.getLinkMans().size());
        tx.commit();
    }

    @Test
    /**
     * 设置fetch="select" lazy="extra"
     */
    public void demo4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 查询5号客户
        Customer customer = session.get(Customer.class, 5l);// 发送一条查询1号客户的SQL语句
        System.out.println(customer.getCust_name());

        System.out.println(customer.getLinkMans().size());// 发送一条select count() from ...;
        tx.commit();
    }

    @Test
    /**
     * 设置fetch="join" lazy=失效
     */
    public void demo5(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        // 查询1号客户
        Customer customer = session.get(Customer.class, 1l);// 发送一条迫切左外连接查询记录
        System.out.println(customer.getCust_name());

        System.out.println(customer.getLinkMans().size());// 不发送
        tx.commit();
    }

    @SuppressWarnings("unchecked")
    @Test
    /**
     * 设置fetch="subselect" lazy="true"
     */
    public void demo6(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL
        for (Customer customer : list) {
            System.out.println(customer.getCust_name());
            System.out.println(customer.getLinkMans().size());// 发送一条子查询
        }

        tx.commit();
    }

    @SuppressWarnings("unchecked")
    @Test
    /**
     * 设置fetch="subselect" lazy="false"
     */
    public void demo7(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL,发送一条子查询
        for (Customer customer : list) {
            System.out.println(customer.getCust_name());
            System.out.println(customer.getLinkMans().size());//
        }

        tx.commit();
    }
}

many-to-one标签上的fecth和lazy的使用

查询到多的一方的对象,去关联查询一的一方的对象

  • fetch:抓取策略,控制SQL语句的格式

    • select:默认值,发送正常形式的sql语句,查询关联对象
    • join:发送采取 迫切左外连接形式的sql语句,查询关联对象
  • lazy:延迟加载,控制查询其关联对象的时候,是否采用延迟加载(SQL语句什么时候进行发送)。

    • proxy:默认值,proxy具体的取值,取决于另一端的class标签上的lazy的值。class标签上lazy的值是什么,proxy就表示什么
    • false:查询关联对象的时候,不采用延迟加载
    • no-proxy:不会使用

fetch:select --------------------- lazy:proxy
fetch:select --------------------- lazy:false
fetch:join --------------------- lazy:失效,在查询客户的时候,采用左外连接,直接就把联系人查出来了

代码实现

package com.day04;

import com.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

/**
 * many-to-one上的fetch和lazy测试
 *
 */
public class HIbernateDemo6 {
    @Test
    /**
     * 默认值
     */
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        LinkMans LinkMans = session.get(LinkMans.class, 1l);// 发送一条查询联系人语句
        System.out.println(LinkMans.getLkm_name());
        System.out.println(LinkMans.getCustomer().getCust_name());// 发送一条select语句查询联系人所关联的客户

        tx.commit();
    }

    @Test
    /**
     * fetch="select" lazy="proxy"
     */
    public void demo2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        LinkMans LinkMans = session.get(LinkMans.class, 1l);// 发送一条查询联系人语句
        System.out.println(LinkMans.getLkm_name());
        System.out.println(LinkMans.getCustomer().getCust_name());// 发送一条select语句查询联系人所关联的客户

        tx.commit();
    }

    @Test
    /**
     * fetch="select" lazy="false"
     */
    public void demo3(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        LinkMans LinkMans = session.get(LinkMans.class, 1l);// 发送一条查询联系人语句,发送一条select语句查询联系人所关联的客户
        System.out.println(LinkMans.getLkm_name());
        System.out.println(LinkMans.getCustomer().getCust_name());// 

        tx.commit();
    }

    @Test
    /**
     * fetch="join" lazy=失效
     */
    public void demo4(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        LinkMans LinkMans = session.get(LinkMans.class, 1l);// 发送一条迫切左外连接查询联系人所关联的客户。
        System.out.println(LinkMans.getLkm_name());
        System.out.println(LinkMans.getCustomer().getCust_name());// 

        tx.commit();
    }
}

批量抓取

什么是批量抓取

批量抓取就是批量抓取多个关联对象 ,使用属性batch-size=“3”,表示批量抓取一次抓取3个关联对象.

获取一的一方的对象,批量抓取关联的多的一方的对象

在一的一方的xml配置文件中的set标签上配置batch-size属性,默认值是1.
批量抓取,sql语句发送的格式和发送的时候是否使用延迟加载,使用fecth和lazy默认的值就可以.
batch-size只是表示在抓取的时候抓取多个,控制抓取关联对象的个数.

获取多的一方的对象,批量抓取关联一的一方的对象

在一的xml配置文件中的class属性上,配置batch-size属性的值,而不是在多的一方的xml配置文件上的many-to-one标签上去设置batch-size的值,标签上也没有该属性.

代码实现

package com.day04;


import com.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import java.util.List;

/**
 * 批量抓取
 *
 */
public class HibernateDemo7 {

    @SuppressWarnings("unchecked")
    @Test
    /**
     * 获取客户的时候,批量抓取联系人
     * 在Customer.hbm.xml中set上配置batch-size
     */
    public void demo1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        List<Customer> list = session.createQuery("from Customer").list();
        for (Customer customer : list) {
            System.out.println(customer.getCust_name());
            for (LinkMans LinkMans : customer.getLinkMans()) {
                System.out.println(LinkMans.getLkm_name());
            }
        }
        tx.commit();
    }

    @SuppressWarnings("unchecked")
    @Test
    /**
     * 获取联系人的时候,批量抓取客户
     * * 在Customer.hbm.xml中<class>上配置
     */
    public void demo2(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction tx = session.beginTransaction();

        List<LinkMans> list = session.createQuery("from LinkMans").list();
        for (LinkMans LinkMans : list) {
            System.out.println(LinkMans.getLkm_name());
            System.out.println(LinkMans.getCustomer().getCust_name());
        }
        tx.commit();
    }
}


发布了60 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44142032/article/details/90489613