【教程】Hibernate 的使用手册 -- Day 04【Hibernate 进阶操作和检索策略】

Hibernate 的查询方式

  • 对象导航查询
    根据 id 查询某个分类(get方法),再查询这个分类下的所有商品(通过set集合)
  • OID查询
    根据 id查询某一条记录,返回对象(get方法)
  • HQL查询
    Query对象,写HQL语句实现查询
  • QBC查询
    Criteria对象,不需要写语句了,使用方法实现
  • 本地SQL查询
    SQLQuery 对象,使用普通SQL实现查询

对象导航查询

  • 查询方式:先根据id查询客户,在得到外键值后根据外键查询所有联系人
//环境准备:只需要基本配置就行
public void selectDemo1(){
	SessionFactory sessionFactory = null;
	Session session = null
	Transaction tx = null;
	try{
		sessionFactory = HibernateUtils.getSessionFactory ();
		session = sessionFactory.opensession();
		tx = session.beginTransaction();
		
		/*    操作    */
		//根据cid=1查询客户
		Customer customer = session.get(Customer.class,1);
		//再查询该客户的所有联系人
		//直接得到客户里面联系人的set集合
		Set<LinkMan> linkman = customer.getSetLinkMan();
		/*    操作    */
		
		tx.commit();//提交
	}catch(Exception e){
		tx.rollback();
	}finally{
		session.close();
		sessionFactory .close();
	}
}
  • set 集合的遍历:增强for循环Iterator迭代器

OID查询

  • 最简单的
  • 根据 id 查询记录:调用sessionget()方法实现

HQL查询

  • 与SQL语句的很像,其中最大区别是HQL操作的实体类及其属性;而SQL操作的是数据库表及表字段。
  • 使用HQL查询操作的时候,使用Query对象
    (1)创建Query对象并传入HQL语句
    (2)调用Query对象里面的方法得到结果

以下代码放入上面代码的操作中即可

查询所有 ★

  • 语句写法:from 实体类名称
//1 创建Query对象
Query query = session.createQuery("from Customer");
//2 调用方法得到结果
List<Customer> list = query.list();
//3 遍历输出
for(Customer c:list){
	System.out.println( c.getCid()+c.getCname() );
}

条件查询 ★

  • 语句写法
  • 精准查询:from 实体类名 where 实体类属性名称=? and 实体类属性名称=?
  • 模糊查询:from 实体类名 where 实体类属性名称 like ? (需要设置模糊查询的查询规则)
//1 创建Query对象
//可以使用别名:from Cusomer as C ,as可以不写,后面就是C.cid
String hql = "from Customer where cid =? and custName=?";
Query query = session.createQuery(hql);
//2 设置值
//第一个参数:?的索引,从0开始
//第二个参数:具体参数值
query.setParameter(0,1);
query.setParameter(1,"demo");
//3 调用方法得到结果
List<Customer> list = query.list();
//4 遍历输出
for(Customer c:list){
	System.out.println( c.getCid()+c.getCname() );
}

排序查询 ★

  • 查询出来的结果按照升序 ASC 或降序 DESC排序
  • 语句写法 from 实体类名称 order by 实体类属性名称 asc|desc
//1 创建Query对象
String hql = "from Customer order by cid desc";
Query query = session.createQuery(hql);
//2 调用方法得到结果
List<Customer> list = query.list();
//3 遍历输出
for(Customer c:list){
	System.out.println( c.getCid()+c.getCname() );
}

分页查询 ★

  • MySQL实现分页:使用limited关键字
    select * from t_customer LIMIT 0,3
    表示从0开始,每一页显示3条记录
  • HQL中实现
    (1)HQL语句中不能使用LIMIT关键字
    (2)Hibernate 的Query对象封装了两个方法实现分页
  • 分页查询用法:可以返回前几条或者中间某几行数据
//1 创建Query对象
String hql = "from Customer";
Query query = session.createQuery(hql);
//2 设置分页的参数
query.setFirstResult(0);//开始位置
query.setMaxResults(3);//每页记录数
//3 调用方法得到结果
List<Customer> list = query.list();
//4 遍历输出
for(Customer c:list){
	System.out.println( c.getCid()+c.getCname() );
}

投影查询

  • 投影查询即查询部分字段值 select id from user
  • 语句写法:select 实体类属性名称,实体类属性名称1 from 实体类名称
  • select 后面不可以用*
//1 创建Query对象
String hql = "select cid from Customer";
Query query = session.createQuery(hql);
//2 调用方法得到结果
List<Object> list = query.list();
//3 遍历输出
for(Object object:list){
	System.out.println(object);
}

聚集函数使用

  • 常用的聚集函数:count / sum / avg / max / min
  • 语句写法:select count(*) from 实体类名称
//1 创建Query对象
String hql = "select count(*) from Customer";
Query query = session.createQuery(hql);
//2 调用方法得到结果
//query对象里有方法可以直接返回Object的形式
//不需要再遍历list获取值
Object obj = query.uniqueResult();
//将Object转换为int,不能直接强行转换为int类型,会产生异常
Long long = (Long) obj;//先转化为Long类型
int count = ling.intValue();//再将Long类型转成int类型
//3 直接输出
System.out.println(count);

HQL多表查询

MySQL多表查询

  • 内连接:互相关联显示
    select * from t_customer c , t_linkman l where c.cid = l.cid
    SELECT * FROM t_customer c INNER JOIN t_linkman l ON c.cid=l.cid
  • 左外连接:左全显示,右关联显示
    SELECT * FROM t_customer c LEFT OUTER JOIN t_linkman l ON cccid=l.cid
  • 右外连接:右全显示,左关联显示
  • SELECT * FROM t_customer c RIGHT OUTER JOIN t_linkman l ON cccid=l.cid

HQL具体实现

以客户和联系人为例

  • 内连接
    from Customer c inner join c.setLinkMan
    返回 listlist 里的每部分都是数组的结构
  • 迫切内连接
    底层实现与内连接相同,区别在于使用内连接返回 list 中每部分是数组,而迫切内连接返回 list 中每部分是对象
    from Customer c inner join fetch c.setLinkMan
  • 左外连接
    from Customer c left outer join c.setLinkMan
  • 迫切左外连接
    from Customer c left outer join fetch c.setLinkMan
  • 右外连接(没有迫切右外连接
    from Customer c right outer join c.setLinkMan

QBC查询

也是操作实体类和属性

  • 主要步骤
    (1) 创建Criteria对象
    (2) 调用方法得到结果

查询所有 ★

//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 调用方法得到结果
List<Customer> list = criteria.list();
//3 遍历输出
for(Customer c:list){
	System.out.println(c.getCid()+"::"+c.getCname());
}

条件查询

  • 使用Restrictions类方法
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 使用criteria对象的方法设置条件值
//使用add方法表示设置条件值
//在add方法里面使用类的方法实现条件设置
criteria.add(Restrictions.eq("cid",1));//表示cid==1
criteria.add(Restrictions.eq("Cname","demo"));//表示cname==demo
//3 调用方法得到结果
List<Customer> list = criteria.list();
//4 遍历输出
for(Customer c:list){
	System.out.println(c.getCid()+"::"+c.getCname());
}

其他的条件设置类方法
在这里插入图片描述

排序查询

  • 调用Order类方法实现
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 设置对那个属性进行排序,以及排序的规则 desc() / asc()
criteria.addOrder(Order.desc("cid"));//根据cid降序排序
//3 调用方法得到结果
List<Customer> list = criteria.list();
//4 遍历输出
for(Customer c:list){
	System.out.println(c.getCid()+"::"+c.getCname());
}

分页查询

  • 设置参数即可
  • 与query对象的方法名一样
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 设置分页的参数 开始位置&显示记录数
criteria.setFirstResult(0);
criteria.setMaxResults(3);
//3 调用方法得到结果
List<Customer> list = criteria.list();
//4 遍历输出
for(Customer c:list){
	System.out.println(c.getCid()+"::"+c.getCname());
}

统计查询

  • 类似于聚集函数的功能,例如:得到整个表格中有多少条记录
  • 使用Projections类方法
//1 创建对象
Criteria criteria = session.createCriteria(Customer.class);
//2 设置统计的功能
criteria.setProjection(Projections.rowCount());
//3 调用方法得到结果
Object obj= criteria.uniqueResult();
Long long = (Long) obj;
int count = long.intValue();
//4 输出
System.out.println(count);

离线查询

  • 离线查询即脱离session来使用的一种查询。使用离线查询可以再其他层对条件进行封装。
  • 在SSH整合以后会经常使用到,当在做一些特别复杂的条件查询的时候
    (1)Servlet 获取数据后向 service 传递很多的参数
    (2)Service 要将这些参数传递给 DAO层
    (3)最后在 DAO 层拼接 SQL 完成查询
  • 而有了离线查询后
    (1)直接在 Servlet 中封装好这些数据,将数据放在 detachedCriteria 对象中传递给 service
    (2)将detachedCriteria从 service 传递给 DAO 层
    (3)DAO层通过session查询数据并返回结果
  • 直接写在 WEB 层,调用任意一个session实现
/*  Servlet  */
//1 创建对象
DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
//2 拼接查询条件
detachedCriteria.add(Restrictions.eq("cid",1));
detachedCriteria.add(Restrictions.eq("Cname","demo"));

/*  经过service传递到DAO层  */

/*  DAO  */
//1 将detachedCriteria关联session
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
//2 得到结果
List<Customer> list = criteria.list();
//3 返回结果
return list;

Hibernate 的检索策略

Hibernate 检索策略分为两类

(1)立即查询:根据id查询,调用get方法,一调用get方法马上发送语句查询数据库

//执行get方法语句之后马上发送sql语句查询数据库
Customer customer = session.get(Customer.class,1);

(2)延迟查询:根据id查询,还有load方法,调用load方法不会马上发送语句查询数据库,只有要得到对象里面的其他值的时候才会发送语句查询数据库

//调用load方法之后不会马上发送sql语句,返回的对象只有id值
Customer customer = session.load(Customer.class,2);
System.out.println(customer.getCid());
//当需要得到该对象里面不是id的其他值的时候才发送语句
//例:需要获得Cname而不是Cid
System.out.println(customer.getCname());

思想:只有需要用的时候才查,不需要的时候就不查;这样能有效的提高性能

延迟查询分成两类

(1)类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送语句;
(2)关联级别延迟:当需要查询某个客户下面的所有联系人时,查询客户的所有联系人的过程是否需要延迟,这个过程称为关联级别查询;Hibernate 默认的优化,不需要做改动

/*  根据cid=1查询客户,再查询该客户的所有联系人  */
//1 查询客户
Customer customer = session.get(Customer.class,1);
//2 再查询该客户下的所有联系人
//可以直接得到客户里面的联系人集合
//得到set集合,但是没有发送语句,此处为关联级别延迟
Set<LinkMan> linkman = customer.getSetLinkMan();
//3 当需要得到联系人的属性值的时候,才发送语句查询数据库
System.out.println(linkman.size());

关联级别延迟操作

  • 映射文件中进行配置:根据客户得到所有的联系人,在客户的映射文件中配置
  • 通过在set标签中设置lazyfetch 属性来实现
<!-- 默认 -->
<set name="setLinkMan" fetch="select" lazy="true">

在这里插入图片描述

极其懒惰即你要什么就给你什么,例如你要linkman的size,那就发送的sql语句中就采用聚集函数count得到数量,效率更加高

Hibernate 的批量抓取

  • 场景:查询所有集合,返回list集合,遍历list集合,得到每个客户,再得到每个客户的所有联系人
//1 查询所有客户
Criteria criteria = session.createCriteria(Customer.class)
Lint<Customer> list = criteria.list();
//2 得到每个客户的联系人
for(Customer c:list){
	System.out.println(c.getCid());
	//每个客户的联系人
	Set<LinkMan> setLinkMan = customer.getSetLinkMan();
	for(LinkMan lm :setLinkMan){
		System.out.println(lm.getLid());
	}
}

一般方法可以实现功能,但是由于要发送过多sql语句,会造成性能消耗非常大,效率地下

  • 批量抓取优化
    根据客户查询联系人,则到客户的配置文件中配置set标签,设置属性batch-size的值,其值没有固定值,值越大,发送语句越少,效率越高java代码不变,仅做set标签配置即可
<set name="setLinkMan" batch-size="10">
发布了27 篇原创文章 · 获赞 12 · 访问量 5184

猜你喜欢

转载自blog.csdn.net/Kobe_k/article/details/104038572
今日推荐