文章目录
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 查询记录:调用
session
的get()
方法实现
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
返回list
,list
里的每部分都是数组的结构 - 迫切内连接
底层实现与内连接相同,区别在于使用内连接返回 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标签中设置
lazy
和fetch
属性来实现
<!-- 默认 -->
<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">