• Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制


    目录

    1. Hibernate的查询方式

    • 在Hibernate中提供了5种查询方式。

    1.1 方式一:OID查询

    • OID查询:Hibernate根据对象的OID(主键)进行检索。
    • 使用get()方法
      • Customer customer = session.get(Customer.class,1L);
    • 使用load()方法
      • Customer customer = session.load(Custoemr.class,1L);

    1.2 方式二:对象导航查询

    • 对象导航检索:Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式。

      LinkMan linkMan = session.get(LinkMan.class,1L);
      Customer customer = linkMan.getCustomer();
      
      Customer customer = session.get(Customer.class,2L);
      Set<LinkMan> linkMans = customer.getLinkMans();
      

    1.3 方式三:HQL方式

    • HQL查询Hibernate Query Language,Hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL。通过session.createQuery(),接收一个HQL进行查询方式。

    1.4 方式四:QBC查询

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

    1.5 方式五:SQL查询

    • SQL查询:通过使用SQL语句进行查询。

    2. 环境搭建

    • 创建一个新项目,导入相关jar包

    • 新建数据库,新建数据表,分别为cst_custoemr和cst_linkman

    • 新建两个实体,分别为Customer和LinkMan

      • Customer中生成toString方法,不包含LinkMan
      • LinkMan中生成toString方法,不包含Customer
    • 准备工具类,配置文件,映射文件

    • 生成测试的数据,该方法执行3次

      /**
       * 	HQL的查询方式的测试类
       * @author itzhouq
       *
       */
      public class HibernateDemo1 {
      	
      	@Test
      	public void test1() {
      		Session session = HibernateUtils.getCurrentSession();
      		Transaction transaction = session.beginTransaction();
      		Customer customer = new Customer();
      		customer.setCust_name("莫尔德");
      		for (int i = 0; i < 10; i++) {
      			LinkMan linkMan = new LinkMan();
      			linkMan.setLkm_name("老马"+i);
      			
      			customer.getLinkMans().add(linkMan);
      			
      			session.save(linkMan);
      		}
      		session.save(customer);
      		transaction.commit();
      		
      	}
      }
      

    3. HQL查询

    3.1 简单查询

    @Test
    	public void test2() {//HQL的简单查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 简单查询
    		Query query = session.createQuery("from Customer");
    		List<Customer> list = query.list();
    		
    		// sql中支持*号的写法:select * from cst_customer;但是在HQL中不支持*号的写法。
    //		Query query2 = session.createQuery("select * from from Customer");// 报错
    //		List<Customer> list2 = query.list();
    		
    		for (Customer customer : list) {
    			System.out.println(customer);
    			
    		}
    		transaction.commit();
    	}
    

    3.2 别名查询

    @Test
    	public void test3() {// 别名查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = 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);
    			
    		}
    		transaction.commit();
    	}
    

    3.3 排序查询

    @Test
    	public void test5() {// 排序查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 排序查询
    		// 默认情况
    		//List<Customer> list = session.createQuery("from Customer order by cust_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);
    			
    		}
    		transaction.commit();
    	}
    

    3.4 条件查询

    @Test
    	public void test4() {// 排序查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 排序查询
    		// 1. 按位置绑定:根据参数的位置进行绑定
    		// 一个条件
    //		Query query = session.createQuery("from Customer where cust_name = ?");
    //		query.setParameter(0, "朱元璋");
    		
    		// 多个条件
    //		Query query = session.createQuery("from Customer where cust_source = ? and cust_name like ?");
    //		query.setParameter(0, "朋友推荐");
    //		query.setParameter(1, "朱%");
    		
    		// 2. 按名称绑定
    		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);
    			
    		}
    		transaction.commit();
    	}
    

    3.4 投影查询

    • 投影查询:查询对象的某个或某些属性
    @Test
    	public void test6() {// 投影查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 投影查询
    		// 单个属性
    //		List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
    //		for (Object customer : list) {
    //			System.out.println(customer);
    //			
    //		}
    		
    		// 多个属性:
    //		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<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
    		for (Object[] customer : list) {
    			System.out.println(Arrays.toString(customer));
    		}
    		
    		transaction.commit();
    	}
    

    3.5 分页查询

    @Test
    	public void test7() {// 分页查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 分页查询
    		Query query = session.createQuery("from LinkMan");
    		query.setFirstResult(20);
    		query.setMaxResults(5);
    		List<LinkMan> list = query.list();
    		for (LinkMan linkMan : list) {
    			System.out.println(linkMan);
    		}
    		
    		transaction.commit();
    	}
    

    3.6 分组统计查询

    @Test
    	public void test8() {// 分组统计查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		// 分组统计查询
    		Object object = session.createQuery("select count(*) from Customer").uniqueResult();
    		System.out.println(object);
    		
    		//分组统计:
    		Query query = session.createQuery("select cust_source,count(*) from Customer group by cust_source");
    		List<Object[]> list = query.list();
    		for (Object[] objects : list) {
    			System.out.println(Arrays.toString(objects));
    		}
    		transaction.commit();
    	}
    

    3.7 HQL的多表查询

    3.7.1 SQL的多表查询

    • 连接查询
      • 交叉连接:笛卡尔积
      • 内连接:innner join(inner可以省略)
        • 隐式内连接:select * from A,B where A.id = B.aid;
        • 显式内连接:select * from A inner join B on A.id = B.aid;
      • 外连接:outer可以省略
        • 左外连接:select * from A left outer join B on A.id = B.id;
        • 右外连接:select * from A right outerjoin B on A.id = B.id;
    • 子查询

    3.7.2 HQL的多表查询

    • 连接查询
      • 交叉连接
      • 内连接:
        • 显式内连接
        • 隐式内连接
        • 迫切内连接
      • 外连接:
        • 左外连接
        • 右外连接
        • 迫切左外连接
    @Test
    	public void test7() { // 多表查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		
    		// SQL:select * from cst_customer c inner join cst_linkman l on c.cust_id = l.lkm_cust_id
    		// HQL:内连接from Customer c inner join c.linkMans
    		// 内连接得到的是一个数组
    		
    //		List<Object[]> list = session.createQuery("from Customer c inner join c.linkMans").list();
    //		for (Object[] objects : list) {
    //			System.out.println(Arrays.toString(objects));
    //		}
    		
    		// HQL:迫切内连接,其实就是在普通的内连接inner join后添加一个关键字fetch.
    		// 迫切内连接的到的是一个对象,在Customer的toString中给定LinkMans可以得到全部字段
    		List<Customer> list2 = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans").list();
    		for (Customer customer : list2) {
    			System.out.println(customer);
    		}
    		
    		transaction.commit();
    	}
    

    4. QBC查询

    4.1 简单查询

    @Test
    	public void test1() { // 简单查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		//获得Criteria的对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		List<Customer> list = criteria.list();
    		for (Customer customer : list) {
    			System.out.println(customer);
    		}
    		
    		transaction.commit();
    	}
    

    4.2 排序查询

    @Test
    	public void test2() { // 排序查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		//获得Criteria的对象
    		Criteria criteria = session.createCriteria(Customer.class);
    //		criteria.addOrder(Order.desc("cust_id"));	// 降序
    		criteria.addOrder(Order.asc("cust_id"));	// 升序
    		List<Customer> list = criteria.list();
    		for (Customer customer : list) {
    			System.out.println(customer);
    		}
    		
    		transaction.commit();
    	}
    

    4.3 分页查询

    @Test
    	public void test3() { // 分页查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		//获得Criteria的对象
    		Criteria criteria = session.createCriteria(LinkMan.class);
    		criteria.setFirstResult(20);
    		criteria.setMaxResults(5);
    		
    		List<LinkMan> list = criteria.list();
    		for (LinkMan linkMan : list) {
    			System.out.println(linkMan);
    		}
    		
    		transaction.commit();
    	}
    

    4.4 条件查询

    @Test
    	public void test4() { // 条件查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		//获得Criteria的对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		// 设置条件
    		/*
    		 * 	= 		eq
    		 * 	>		gt
    		 * 	>=		ge
    		 * 	<		lt
    		 * 	<=		le
    		 * 	<>		ne
    		 * 	like
    		 * 	in
    		 * 	and
    		 * 	or
    		 */
    		criteria.add(Restrictions.eq("cust_source", "小广告"));
    		criteria.add(Restrictions.like("cust_name", "李%"));
    		List<Customer> list = criteria.list();
    		for (Customer customer : list) {
    			System.out.println(customer);
    		}
    		
    		transaction.commit();
    	}
    

    4.5 统计查询

    @Test
    	public void test5() { // 条件查询
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		//获得Criteria的对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		/**
    		 * 	add		:普通的条件。where后面条件
    		 * 	addOrder:排序
    		 * 	setProjecttion:聚合函数和group by having
    		 */
    		
    		criteria.setProjection(Projections.rowCount());
    		Long num = (Long) criteria.uniqueResult();
    		System.out.println(num);
    		
    		transaction.commit();
    	}
    

    4.6 离线条件查询(***)DetachedCriteria

    • 离线条件查询在前台需要传递多个条件,用于筛选的时候很方便,可以不用在dao层拼接字符串

      离线条件查询分析图

    • 代码

    @Test
    	public void test6() { // 离线条件查询
    		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();
    	}
    

    5. SQL查询

    
    	@Test
    	public void test1() {
    		Session session = HibernateUtils.getCurrentSession();
    		Transaction transaction = session.beginTransaction();
    		
    		// 调用的createSQLQuery,返回的值遍历后是数组形式的集合
    //		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);	//封装到实体Customer中
    		List<Customer> list = sqlQuery.list();
    		for (Customer customer : list) {
    			System.out.println(customer);
    		}
    		
    		transaction.commit();
    	}
    

    6. Hibernate的抓取策略

    6.1 延迟加载的概述

    6.1.1 什么是延迟加载

    • 延迟加载:lazy(懒加载)。执行到该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。

    6.1.2 延迟加载的分类

    • 类级别的延迟加载

      • 指的是通过load方法查询某个对象的时候,是否采用延迟加载。session.load(Customer.class,1L);
      • 类级别的延迟加载通过<class>上的lazy进行配置。让lazy失效的方法有:
        • 将lazy设置为false
        • 将持久化类使用final修改
        • Hibernate.ininialize()
    • 关联级别的延迟加载

      • 指的是在查询到某个对象的时候,查询其关联对象的时候,是否采用延迟加载。

        Customer customer = session.get(Customer.class,1L);
        customer.getLinkMans();
        //通过客户获得联系人的时候,联系人对象是否采用了延迟记载,称为关联级别的延迟加载。
        
      • 抓取策略往往会和关联级别的延迟加载一起使用,优化语句。

    6.2 抓取策略

    Customer.hbm.xml

    <set name="linkMans" fetch="select" lazy="true">
        <!-- column多的一方的外键的名称 -->
        <key column="lkm_cust_id"></key>
        <!-- class:多的一方的类的全限定名 -->
        <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
    </set>
    

    6.2.1 抓取策略概述

    • 通过一个对象抓取到关联对象需要发送SQL语句,SQL语句如何发送,发送成什么样格式?这些可以通过策略进行配置。
      • 通过<set>或者<many-to-one>上的fetch属性进行配置
      • fetch和这些标签上的lazy如何设置,优化发送的SQL语句。

    6.2.2 set上的fetch和lazy

    • fetch:抓取策略,控制SQL语句格式
      • select:默认值,发送普通的select语句,查询关联对象
      • join:发送一条迫切左外连接查询关联对象。
      • subeselect:发送一条子查询查询其关联对象。
    • lazy:延迟加载,控制查询关联对象的时候是否采用延迟加载
      • true:默认值,查询关联对象的时候,采用延迟加载
      • false:查询关联对象的时候,不采用延迟加载
      • extra:及其懒惰。
    • 实际开发过程中,一般采用默认值。如果有特殊需求,可能需要配置join。

    6.2.3 many-to-one上的fetch和lazy

    • fetch:抓取策略,控制SQL语句格式
      • select:默认值,发送普通的select语句,查询关联对象。
      • join:发送一条迫切左外连接
    • lazy:延迟加载,控制查询关联对象的时候是否采用延迟加载
      • proxy:默认值,proxy具体的取值,取决于另一端的class上的lazy的值。
      • false:查询关联对象,不采用延迟。
      • no-proxy:不用
    • 在实际开发过程中,一般采用默认值。如果有特殊的需求,可能需要配置join。

    6.2.4 批量抓取

    • 一批关联对象一起抓取,betch-size。

      package com.itzhouq.hibernate.demo;
      
      import java.util.List;
      
      import org.hibernate.Session;
      import org.hibernate.Transaction;
      import org.junit.Test;
      
      import com.itzhouq.hibernate.domain.Customer;
      import com.itzhouq.hibernate.domain.LinkMan;
      import com.itzhouq.hibernate.utils.HibernateUtils;
      
      /*
       * 	批量抓取测试
       */
      public class HibernateDemo4 {
      
      	
      	@Test
      	public void test1() {
      		// 获取客户的时候,批量抓取联系人
      		// 在Customer.hbm.xml中set上配置batch-size
      		Session session = HibernateUtils.getCurrentSession();
      		Transaction transaction = session.beginTransaction();
      		List<Customer> list = session.createQuery("from Customer").list();
      		for (Customer customer : list) {
      			System.out.println(customer.getCust_name());
      			for (LinkMan linkMan : customer.getLinkMans()) {
      				System.out.println(linkMan.getLkm_name());
      			}
      		}
      		
      		transaction.commit();
      	}
      }
      
      <set name="linkMans" batch-size="5">
          <!-- column多的一方的外键的名称 -->
          <key column="lkm_cust_id"></key>
          <!-- class:多的一方的类的全限定名 -->
          <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/>
      </set>
      
  • 相关阅读:
    软件开发流程
    计算机与生命体的类比
    cnBeta过期评论查看器,再次更新
    用Ruby写的离线浏览代理服务器,重要更新
    计算机编程常用词汇
    网站创意:商品知识库
    Node.JS进行简单新技术分析及环境搭建
    MongoDB (0)写在前面
    基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)
    MongoDB (5)不仅仅是数据库
  • 原文地址:https://www.cnblogs.com/itzhouq/p/hibernate04.html
Copyright © 2020-2023  润新知