今天内容
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 * from 表1 corss join 表2
* 自然连接
* 表中所有同名列默认作为连接条件
* select * from 表1 natural join 表2
* using 子句连接
* 可以显示指定某同名列作为连接条件
* select * from 表1 join 表2 using(name)
* on子句连接(内连接)
* 每一个on子句指定一个连接条件
* select * from 表1 (inner) join 表2 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();
离线查询条件
- 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语句
- 关联级别查询加载策略
这里太多了,总结一句话,用默认的就对了