Hibernate的HQL选择、投影、排序、分页、聚合分组、连接查询、QBC分页、排序、条件、离线查询、hibernate整合c3p0连接池、事务隔离级别、hibernate中设置隔离级别-day04

第一节 HQL查询

1.1 HQL简介

  • HQL(Hibernate Query Language) 描写对象操作的一种查询语言,Hibernate特有。
  • HQL的语法与SQL基本一致,不同的是HQL是面向对象的查询,查询的是对象和对象中的属性。
  • HQL的关键字不区分大小写,但类名和属性区分大小写
  • 语法示例:
    SELECT 别名/属性名/表达式
    FROM 实体 AS 别名
    WHERE 过滤条件
    GROUP BY 分组条件
    HAVING 分组后的结果的过滤条件
    ORDER BY 排序条件

1.2 案例1:查询所有客户

  • 在day03的基础上,进一步使用hql。
	//案例1:查询所有客户
	@Test
	public void test1(){
    
    
		Session session = HibernateUtils.openSession();
		//查询所有客户
		Query query = session.createQuery("from Customer");
		//查询后的结果会封装到一个list集合中
		List<Customer> list = query.list();
		//遍历
		for (Customer customer : list) {
    
    
			System.out.println(customer.getCustomerName());
		}
		session.close();
	}

在这里插入图片描述

在这里插入图片描述

1.3 案例2:选择查询

	//案例2:选择查询
	@Test
	public void test2(){
    
    
		Session session = HibernateUtils.openSession();
		//查询客户带条件
		//Query query = session.createQuery("from Customer where id = 1");
		Query query = session.createQuery("from Customer where id = ? ");

		//起别名
		//Query query1 = session.createQuery("from Customer c where c.id = ? ");
		Query query1 = session.createQuery("select c from Customer c where c.id = ? ");
		//设置参数从0开始
		query.setParameter(0,1);
		query1.setParameter(0,2);

		//查询后的结果会封装到一个list集合中
		List<Customer> list = query.list();
		//遍历
		for (Customer customer : list) {
    
    
			System.out.println(customer.getCustomerId()+":"+customer.getCustomerName());
		}

		//只获取一条记录
		Customer customer1 = (Customer) query1.uniqueResult();
		System.out.println(customer1.getCustomerId()+":"+customer1.getCustomerName());

		session.close();
	}

在这里插入图片描述

1.4 案例3:投影查询

	//案例3:投影查询1
	@Test
	public void test3(){
    
    
		Session session = HibernateUtils.openSession();
		//指定查询字段
		Query query = session.createQuery("select  c.id,c.customerName from Customer c ");

		//这种查询出来的结果是一个数组类型的集合
		List<Object[]> list = query.list();

		//遍历集合,集合中的每一个元素是一个数组
		for (Object[] objects : list) {
    
    
			for (Object object : objects) {
    
    
				System.out.println(object);
			}
			System.out.println("------------");
		}

		session.close();
	}

在这里插入图片描述

	//案例3:投影查询2
	@Test
	public void test4(){
    
    
		Session session = HibernateUtils.openSession();
		//指定查询字段,封装到集合对象中,但是Customer必须要提供对应的构造方法
		Query query = session.createQuery("select new Customer(c.id,c.customerName) from Customer c ");

		//这种查询出来的结果是Customer集合
		List<Customer> list = query.list();

		//遍历
		for (Customer customer : list) {
    
    
			System.out.println(customer);
		}

		session.close();
	}

在这里插入图片描述

1.5 案例4:排序

	//案例4:排序
	@Test
	public void test5(){
    
    
		Session session = HibernateUtils.openSession();
		//asc升序  desc降序
		List<Customer> list = session.createQuery("from Customer c order by c.id desc ").list();
		//需要Customer提供对应的构造方法,否则报错
		//List<Customer> list = session.createQuery("select new Customer(c.id,c.customerName) from Customer c order by c.id desc ").list();
		//遍历
		for (Customer customer : list) {
    
    
			System.out.println(customer);
		}

		session.close();
	}

在这里插入图片描述

1.6 案例5:分页

	//案例5:分页
	@Test
	public void test6(){
    
    
		Session session = HibernateUtils.openSession();
		//分页 limit ?,?
		Query query = session.createQuery("from Customer ");
		//当前页(pageCode)
		query.setFirstResult(0);//相当于limit 0,2 第一页,每页显示条数2
		//每页显示个数(pageSize)
		query.setMaxResults(2);
		//2,2 第二页,每页显示条数2
		//第一页开始0、第二页开始2,计算方法:(页数-1)*每页显示条数
		List<Customer> list = query.list();
		for (Customer customer : list) {
    
    
			System.out.println(customer);
		}
		session.close();
	}

在这里插入图片描述

1.7 案例6:聚合函数和分组查询

	//案例6:聚合函数和分组查询
	@Test
	public void test7(){
    
    
		Session session = HibernateUtils.openSession();
		//1.聚合函数
		//1.1总记录数 count
		Query query1 = session.createQuery("select count(*) from Customer ");
		//返回的是long类型
		long count = (long) query1.uniqueResult();
		System.out.println("客户表的总记录数为:"+count);

		//1.2平均数 avg
		Query query2 = session.createQuery("select avg(c.id) from Customer c ");
		//返回的是Double类型
		Double avg = (Double) query2.uniqueResult();
		System.out.println("客户表id的平均数为:"+avg);

		//1.3分组 group by【根据客户分组,查看客户有多少张订单】
		Query query3 = session.createQuery("select o.customer,count(o) from Order o group by o.customer having count(o) > 1");

		//这种查询出来的结果是Customer集合
		List<Object[]> list = query3.list();

		//遍历集合,集合中的每一个元素是一个数组
		for (Object[] objects : list) {
    
    
			System.out.println("客户信息:"+objects[0]+" 订单数:"+objects[1]);
		}
		
		session.close();
	}

在这里插入图片描述
在这里插入图片描述

1.8 案例7:连接查询

  • INNER JOIN:在表中存在至少一个匹配时,INNER JOIN 关键字返回行。
  • LEFT OUTER JOIN:关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行
  • RIGHT OUTER JOIN:关键字会右表 (table_name2) 那里返回所有的行,即使在左表 (table_name1) 中没有匹配的行。
程序中指定的连接查询类型 HQL语法 适用范围
内连接 inner join | join 适用于有关联关系的持久化类
迫切内连接 inner join fetch | join fetch
隐式内连接
左外连接 left outer join | left join
迫切左外连接 left outer join fetch | left join fetch
右外连接 right outer join | outer join
交叉连接 ClassA ClassB 适用于不存在关联关系的持久化类

1.交叉连接 ,等效 sql 笛卡尔积

	//交叉连接
    @Test
    public void test1(){
    
    
        Session session = HibernateUtils.openSession();
        //HQL的交叉连接等效sql的笛卡尔积
        List<Object[]> list = session.createQuery("from Customer c ,Order o ").list();
        for (Object[] objects : list) {
    
    
            System.out.println("客户:"+objects[0]+" 订单:"+objects[1]);
        }
        session.close();
    }

在这里插入图片描述

扫描二维码关注公众号,回复: 12014611 查看本文章

左边客户表的每一条记录都与右边订单表的每一条记录匹配,有很多不符合条件的数据,下面会使用隐式内连接过滤掉。

2.隐式内连接,等效 sql 隐式内连接

	//隐式内连接【join】
    @Test
    public void test2(){
    
    
        Session session = HibernateUtils.openSession();
        //隐式内连接相当于在笛卡尔积上加了过滤条件
        List<Object[]> list = session.createQuery("from Customer c ,Order o where c = o.customer").list();
        for (Object[] objects : list) {
    
    
            System.out.println("客户:"+objects[0]+" 订单:"+objects[1]);
        }
        session.close();
    }

在这里插入图片描述

3.内连接,等效sql内连接

 	//内连接【inner join】
    @Test
    public void test3(){
    
    
        Session session = HibernateUtils.openSession();
        //显示内连接(非迫切)
        //非迫切:返回的数据将客户和订单对象封装到数组 Object[] objects = {Customer,Order}
        List<Object[]> list = session.createQuery("from Customer c inner join c.orders").list();
        for (Object[] objects : list) {
    
    
            System.out.println("客户:"+objects[0]+" 订单:"+objects[1]);
        }
        session.close();
    }

在这里插入图片描述

4.迫切内连接,hibernate底层使用内连接

	//迫切内连接【inner join fetch】
    @Test
    public void test4(){
    
    
        Session session = HibernateUtils.openSession();
        //显示内连接(迫切)
        //迫切:返回的数据封装到List中的客户对象中 List<Customer>
        List<Customer> list = session.createQuery("from Customer c inner join fetch c.orders").list();
        for (Customer customer : list) {
    
    
            System.out.println(customer);
        }
        session.close();
    }

在这里插入图片描述

注意:此处Customer中生成的toString可以包含orders,或者可以直接customer.getOrders()获取封装到customer的订单信息。但是Order中就不要生成包含customer的toString,否则死循环报错。
内连接和迫切内连接内部使用的都是inner join sql语句
它们的区别是有没有使用fetch和返回的数据最终封装到数组中还是对象中,当然它们都要先封装到集合中。

5.左外连接,等效sql左外连接

 	//左外连接【left outer join】
    @Test
    public void test5(){
    
    
        Session session = HibernateUtils.openSession();
        //左外连接:左表(客户)中如果没有右表(订单)的匹配数据,左表记录也会显示。
        List<Object[]> list = session.createQuery("from Customer c left outer join c.orders").list();
        for (Object[] objects : list) {
    
    
            System.out.println("客户:"+objects[0]+" 订单:"+objects[1]);
        }
        session.close();
    }

在这里插入图片描述

6.内连接与左外连接的区别

左外连接和内连接的区别:内连接左边与右边一定要相等(有交集),必须要能匹配到否则不显示;左外连接不相等也显示。

  • 例如:添加一个客户shu3,而不添加对应的订单信息
    在这里插入图片描述
  • 执行内连接,还是6条记录,因为没有客户shu3匹配的订单
    在这里插入图片描述
  • 执行左外连接,7条记录,没有客户shu3的订单也显示它
    在这里插入图片描述

7.迫切左外连接,hibernate底层使用左外连接

	//迫切左外连接【left outer join fetch】
    @Test
    public void test6(){
    
    
        Session session = HibernateUtils.openSession();
        //也是封装成一个对象
        List<Customer> list = session.createQuery("from Customer c left outer join fetch c.orders").list();
        for (Customer customer : list) {
    
    
            System.out.println("客户:"+customer+" 订单:"+customer.getOrders());
        }
        session.close();
    }

在这里插入图片描述

8.右外连接(迫切),等效sql右外连接

	//右外连接(迫切)【right outer join (fetch)】
    @Test
    public void test7(){
    
    
        Session session = HibernateUtils.openSession();
        //右外连接:右表(订单)中如果没有左表(客户)的匹配数据,右表记录也会显示。
        List<Object[]> list = session.createQuery("from Customer c right outer join c.orders").list();
        for (Object[] objects : list) {
    
    
            System.out.println("客户:"+objects[0]+" 订单:"+objects[1]);
        }
        session.close();
    }
  • 添加一个没有客户的订单信息
    在这里插入图片描述
  • 使用右外连接(迫切)也能查询到
    在这里插入图片描述

注意:使用迫切右外连接的时候注意防止空指针异常,比如customer为null,使用customer.getOrders()会报空指针异常错误,也可以在Customer中直接把orders加入toString,但是在Order中toString就不能加customer注意toString死循环。

1.9 案例8:命名查询

  • HQL语句写在java文件里编译后会变成.class文件无法修改,如果web项目打成war包或项目上线后要修改hql语句,要重新编译项目打包
  • 我们可以在hibernate映射文件hbm.xml中命名查询语句,然后使用java从hbm.xml取出hql语句,这样,以后的开发,可以直接在hbm.xml中配置,使得hql灵活使用。

在这里插入图片描述

  • 通过查看hibernate-mapping-3.0.dtd文件,可以知道query放的位置
    在这里插入图片描述
    在这里插入图片描述
//命名查询:把hql写在映射文件中,通过session的getNameQuery来返回一个Query对象
    @Test
    public void test1(){
    
    
        Session session = HibernateUtils.openSession();
        //把hql写在映射文件中,会比较灵活(web项目打成war包后或项目上线后也可以修改hql)
        //第一种:写在类class标签里,必须要写在末尾,这种hql是局部的,(找局部的hql需要提供包名)
        Query query1 = session.getNamedQuery("com.it.hibernate.domain.Customer.hql1");
        List<Object> list = query1.list();
        for (Object o : list) {
    
    
            System.out.println(o);
        }
        System.out.println("------------------");
        //第二种:写在hibernate-mapping里,最好写在末尾,这种hql是全局的,(找全局的hql不需要提供包名)
        Query query2 = session.getNamedQuery("hql2");
        query2.setParameter(0,1);
        System.out.println(query2.list());
        session.close();
    }

在这里插入图片描述

第二节 QBC查询

2.1 QBC简介

  • QBC(query by criteria)条件查询,hibernate提供的纯面向对象查询语言,提供直接使用PO对象进行操作。
  • 上面还要写少量的hql,使用criteria将可以完全不使用sql。

一些概念:
PO:persistent object ,用于与数据库交互数据。–dao层 (JavaBean + hbm )
BO:Business object 业务数据对象。–service层
VO:Value Object 值对象。–web层

2.2 QBC查询所有客户

在这里插入图片描述

//qbc简单查询(查询所有客户信息)
    @Test
    public void test1(){
    
    
        Session session = HibernateUtils.openSession();
        Criteria criteria = session.createCriteria(Customer.class);
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
    
    
            System.out.println(customer);
        }
        session.close();
    }

在这里插入图片描述

2.3 QBC分页

在这里插入图片描述

	//qbc分页
    @Test
    public void test2(){
    
    
        Session session = HibernateUtils.openSession();
        Criteria criteria = session.createCriteria(Order.class);
        criteria.setFirstResult(0);//第一页0,第二页3,第三页6
        criteria.setMaxResults(3);//每页条数3
        List<Order> list = criteria.list();
        for (Order order : list) {
    
    
            System.out.println(order);
        }
        session.close();
    }

在这里插入图片描述

2.4 QBC排序

//qbc排序
    @Test
    public void test3(){
    
    
        Session session = HibernateUtils.openSession();
        Criteria criteria = session.createCriteria(Order.class);
        //这里addOrder不是添加订单的意思,是排序的意思,
        //还要找到addOrder里Order排序的包名是 org.hibernate.criterion
        criteria.addOrder(org.hibernate.criterion.Order.desc("id"));//降序 desc
        //criteria.addOrder(org.hibernate.criterion.Order.asc("id"));//升序 asc
        List<Order> list = criteria.list();
        for (Order order : list) {
    
    
            System.out.println(order);
        }
        session.close();
    }
  • 根据id降序展示
    在这里插入图片描述

2.5 QBC条件查询

//qbc条件查询
    @Test
    public void test4(){
    
    
        Session session = HibernateUtils.openSession();
        Criteria criteria = session.createCriteria(Order.class);
        //1.模糊查询 like
        //criteria.add(Restrictions.like("orderName","%8%"));//订单名包含8的
        //criteria.add(Restrictions.like("orderName","iphone%"));//订单名以 iphone开头的
        //criteria.add(Restrictions.like("orderName","%6"));//订单名以 6结尾的
        //criteria.add(Restrictions.like("orderName","_p%"));//订单名第2位是p的
        //...
        //2.【 eq = 】【 ge >= 】【 gt > 】
        //【 lt < 】【 le <= 】 要查看更多可按住 Ctrl 点 Restrictions
        criteria.add(Restrictions.gt("id",4));//查看id大于4的订单
        //上面的条件可以结合查询,可以criteria.add多条组合
        List<Order> list = criteria.list();
        for (Order order : list) {
    
    
            System.out.println(order);
        }
        session.close();
    }
  • 查询id值大于4的订单
    在这里插入图片描述

2.6 离线查询【了解】

  • DetachedCriteria离线查询对象,不需要使用Session就可以拼凑查询条件。一般使用在web层或service层拼凑。将此对象传递给dao层,此时将与session进行绑定执行查询。
	//qbc离线查询
    @Test
    public void test5(){
    
    

        //查询名字shu的客户

        //离线查询放在service/web层======================================================
        //拼凑查询条件【离线查询对象】
        DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
        detachedCriteria.add(Restrictions.eq("customerName","shu"));

        //原来放在dao层======================================================
        Session session = HibernateUtils.openSession();
        //Criteria criteria = session.createCriteria(Customer.class);
        //criteria.add(Restrictions.eq("customerName","shu"));
        Criteria criteria = detachedCriteria.getExecutableCriteria(session);//要与session绑定
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
    
    
            System.out.println(customer);
        }
        session.close();
    }

在这里插入图片描述

第三节 hibernate常见配置

3.1 整合c3p0连接池

  • 虽然前面操作数据库是使用session,但是hibernate的本质还是封装jdbc,所以底层还是使用connection,所以要使用连接池。

第一步:导入c3p0的jar包

  • hibernate框架中提供了c3p0的jar包
    在这里插入图片描述
  • 将它复制到你为hibernate项目放jar包的文件夹中
    在这里插入图片描述
  • 打开IDEA的Project Structure
    在这里插入图片描述
  • 添加jar
    在这里插入图片描述
  • 导入成功
    在这里插入图片描述

第二步:配置c3p0

  • 找到这个hibernate配置文件中c3p0的配置
    在这里插入图片描述
  • 将以下选项配置到hibernate.cfg.xml文件中
    在这里插入图片描述
    在这里插入图片描述
  • hibernate.cfg.xml中添加
    在这里插入图片描述
		<!--配置c3p0-->
		<!--
		#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider
		//c3p0提供者
		#hibernate.c3p0.max_size 2 //最大连接数,同时最多得到的connection数
		#hibernate.c3p0.min_size 2 //最小连接数
		#hibernate.c3p0.timeout 5000 //连接超时时间5000毫秒(5秒)
		#hibernate.c3p0.max_statements 100 //最多可以创建Statements对象的个数,就是可以执行SQL语句的对象的个数
		#hibernate.c3p0.idle_test_period 3000 //检查连接池中所有空闲连接的间隔时间,单位为秒
		#hibernate.c3p0.acquire_increment 2 //连接池中连接耗尽了一次性增加2个
		#hibernate.c3p0.validate false //每次都验证连接是否可用
		-->
		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
		<property name="hibernate.c3p0.max_size">2</property>
		<property name="hibernate.c3p0.min_size">2</property>
		<property name="hibernate.c3p0.timeout">5000</property>
		<property name="hibernate.c3p0.max_statements">100</property>
		<property name="hibernate.c3p0.idle_test_period">3000</property>
		<property name="hibernate.c3p0.acquire_increment">2</property>
		<property name="hibernate.c3p0.validate">false</property>

第三步:测试

  • 随便执行一个使用到session的程序
  • 如下图,初始化c3p0连接池,配置成功
    在这里插入图片描述

第四节 事务的隔离级别

  • 为什么有事务的隔离级别?
  • 解决多线程访问数据库的问题。
  • 一组业务操作,要么全部成功,要么全部不成功。

特性:ACID

  • 原子性:整体 【原子性是指事务包含的所有操作要么全部成功,要么全部失败】
  • 一致性:数据 【一个事务执行之前和执行之后都必须处于一致性状态】
  • 隔离性:并发 【对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。】
  • 持久性:结果 【持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的】

隔离问题

  • 脏读:一个事务读到另一个事务未提交的内容【读取未提交内容】
    在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其它级别好多少。

  • 不可重复读:一个事务读到另一个事务已提交的内容(insert)【读取提交内容】
    这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。

  • 虚读(幻读):一个事务读到另一个事务已提交的内容(update)
    这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。

  • Serializable(可串行化)
    这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

隔离级别–解决问题

  • read uncommittd,读未提交。存在3个问题。
  • read committed,读已提交。解决:脏读。存在2个问题。
  • repeatable read ,可重复读。解决:脏读、不可重复读。存在1个问题。
  • serializable,串行化。单事务。没有问题。
    在这里插入图片描述

Hibernate中设置隔离级别

  • 在hibernate.cfg.xml 配置hibernate.connection.isolation
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_43414199/article/details/108411859
今日推荐