Hibernate的查询方式
在Hibernate中提供了很多种查询方式,共提供了五种查询方式。
一、Hibernate的查询方式:OID查询
OID检索:Hibernate根据对象的OID(主键)进行检索
- 使用get方法
Customer customer = session.get(Customer.class,1l);
- 使用load方法
Customer customer = session.load(Customer.class,1l);
二、Hibernate的查询方式:对象导航检索
对象导航检索:Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式。
// 1
LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();
// 2
Customer customer = session.get(Customer.class,2l);
Set<LinkMan> linkMans = customer.getLinkMans();
三、Hibernate的查询方式:HQL检索
HQL查询:Hibernate Query Language,Hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL。通过session.createQyery()接收一个HQL进行查询的方式。
1、初始化数据
@Test
/**
* 初始化数据
*/
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建一个客户
Customer customer = new Customer();
customer.setCust_name("李前");
for (int i = 1; i <= 10; i++) {
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("乔伊"+i);
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
session.save(linkMan);
}
session.save(customer);
transaction.commit();
}
2、HQL的简单查询
查询所有: from 实体类名称
@Test
//HQL简单查询
public void demoe2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 简单查询
Query query = session.createQuery("from Customer"); // from后面是类名,而不是表名。
List<Customer> list = query.list();
// sql中支持*号写法:select * from cst_customer;但是HQL中不支持*号写法。
/*Query query = session.createQuery("select * from Customer");//报错
List<Customer> list = query.list();*/
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
注意:HQL语句中,from后面是类名,而不是表名。
3、HQL的别名查询
别名查询: from 实体类名称 别名
别名查询: select 别名 from 实体类名称 别名
@Test
// HQL别名查询
public void demoe3() {
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();
}
4、HQL的排序查询
排序查询:from 实体类名称 order by 实体类属性名称 asc/desc
@Test
// HQL排序查询
public void demoe4() {
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();
}
5、HQL的条件查询
hql条件查询语句写法:
- 按位置绑定:根据参数的位置进行绑定
- from 实体类名称 where 实体类属性名称=? and实体类属性名称=?
- from 实体类名称 where 实体类属性名称 like ?
- 按名称绑定
- 第一步:from 实体类名 where 实体类属性名称 = :aaa(随便起一个名字)
- 第二步:query.setParameter(“aaa”, “条件”);
@Test
// HQL条件查询
public void demoe5() {
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, "李%");
List<Customer> list = query.list();*/
// 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();
}
- setParameter(int arg0, Object arg1):Query-Query方法的两个参数:
此方法用于按位置绑定查询。- 第一个参数:int类型是 ? 位置,?位置是从0开始。
- 第二个参数:具体的参数值。
- setParameter(String arg0, Object arg1):Query-Query方法的两个参数:
此方法用于按名称绑定查询。- 第一个参数:String类型是随便起的名字,比如aaa。
- 第二个参数:具体的参数值。
6、HQL的投影查询
投影查询:查询对象的某个或某些属性。
投影查询hql语句写法:
(1)select 实体类属性名称1, 实体类属性名称2 from 实体类名称
(2)select 后面不能写 * ,不支持的
@Test
// HQL投影查询
public void demoe6() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 投影查询
// 单个属性
/*List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
for (Object object : list) {
System.out.println(object);
}*/
// 多个属性
/*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<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
例:要查询cust_name和cust_source两个属性,需要在Customer实体类中加入无参构造和只包含这两个属性的有参构造。
public Customer() {
super();
// TODO Auto-generated constructor stub
}
public Customer(String cust_name, String cust_source) {
super();
this.cust_name = cust_name;
this.cust_source = cust_source;
}
7、HQL的分页查询
- mysql实现分页
select * from t_customer Limit 0,3;
- 在hql中实现分页
(1)在HQL操作中,在语句里面不能写limit,hibernate的Query对象封装两个方法实现分页操作
@Test
// HQL分页查询
public void demoe7() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 分页查询
Query query = session.createQuery("from LinkMan");
query.setFirstResult(10);
query.setMaxResults(10);
List<LinkMan> list = query.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
transaction.commit();
}
8、HQL的分组统计查询
-
常用的聚集函数
count、sum、avg、max、min -
hql聚集函数语句写法
(1)查询表记录数
select count(*) from 实体类名称
@Test
// HQL分组统计查询
public void demoe8() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 聚合函数的使用:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
// 分组统计
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source having count(*)>=2").list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
transaction.commit();
}
- 报错处理
// 聚合函数的使用:count(),max(),min(),avg(),sum()
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
int count = (int) object;
System.out.println(count);
解决方法1:
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
// 解决1
Long lobj = (Long) object;
int count = lobj.intValue();
System.out.println(count);
解决方法2:
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);
HQL的多表查询
SQL的多表查询
1、连接查询
- 交叉连接:笛卡尔积
SELECT * FROM A,B;
- 内连接:inner join(inner可省略),两表的交集
- 隐式内连接
- 显示内连接
// 隐式内连接
SELECT * FROM A,B WHERE A.id = B.aid;
// 显示内连接
SELECT * FROM A INNER JOIN B ON A.id = B.aid;
- 外连接
- 左外连接:letf outer join(outer可省略)
- 右外连接:right outer join(outer可省略)
// 左外连接
SELECT * FROM A LEFT OUTER JOIN B ON A.id = B.aid;
//右外连接
SELECT * FROM A RIGHT OUTER JOIN B ON A.id = B.aid;
- 子查询
HQL的多表查询
- 连接查询
- 交叉连接
- 内连接
- 显示内连接
- 隐式内连接
- 迫切内连接
- 外连接
- 左外连接
- 右外连接
- 迫切左外连接
@Test
// HQL多表查询
public void demoe9 () {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 多表查询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。
// from Customer c inner join fetch c.linkMans
// fetch的作用:通中Hibernate,将另一个对象的数据封装倒=到该对象中。
List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMans").list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
内连接和迫切内连接的区别(简单理解):内连接是封装为Objecr数组了,迫切内连接是封装到一个对象里边去了。
四、Hibernate的查询方式:QBC检索
QBC查询:Query By Criteria,条件查询。是一种更加面向对象的查询方式。
1、简单查询
查询所有:
- 创建Criteria对象
- 调用方法得到结果
@Test
// 简单查询
public void demo1() {
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();
}
2、排序查询
调用方法:
- asc(String propertyName):Order-Order
- desc(String propertyName):Order-Order
@Test
// 排序查询
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 排序查询
Criteria criteria = session.createCriteria(Customer.class);
//criteria.addOrder(Order.asc("cust_id"));//升序
criteria.addOrder(Order.desc("cust_id"));//降序
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
3、分页查询
开始位置计算公式: (当前页-1)*每页记录数
@Test
// 分页查询
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 分页查询
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(10);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
transaction.commit();
}
4、条件查询
没有语句,使用封装的方法实现
@Test
// 条件查询
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 条件查询
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", "李%"));
criteria.add(Restrictions.or(Restrictions.like("cust_name", "刘%"),Restrictions.like("cust_name", "邓%")));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
5、统计查询
@Test
// 统计查询
public void demo5() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 统计查询
Criteria criteria = session.createCriteria(Customer.class);
/**
* add:普通条件,where后面条件
* addOrder:排序
* setProjection:聚合函数 和 group by、having
*/
criteria.setProjection(Projections.rowCount());
Long count = (Long) criteria.uniqueResult();
System.out.println(count);
transaction.commit();
}
6、离线条件查询(SSH)-DetachedCriteria
@Test
// 离线条件查询
public void demo6() {
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();
}
五、Hibernate的查询方式:SQL检索
1、SQL查询
SQL查询:通过使用sql语句进行查询
@Test
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
/*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);
List<Customer> list = sqlQuery.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
Hibernate的抓取策略(优化)
1、延迟加载
延迟加载:lazy(懒加载)。执行该行代码的时候,不会发送语句去进行查询,在真正使用这个对象的属性的时候才会发送SQL语句进行查询。
延迟加载的分类
-
类级别的延迟加载
指的是通过load方法查询某个对象的时候,是否使用延迟。session.load(Customer.class,1l);- 类级别的延迟加载通过<class>上的lazy进行配置。如果想让lazy失效:
- 将lazy设置为false。
- 将持久化类用final修饰。
- 调用Hibernate.initialize()。
- 类级别的延迟加载通过<class>上的lazy进行配置。如果想让lazy失效:
-
关联级别的延迟加载
指的是在查询某个对象的时候,查询其关联对象的时候是否会采用延迟加载。
Customer customer = session.get(Customer.class,1l);
customer.getLinkMans();—通过客户获得联系人的时候,联系人对象是否使用了延迟加载,称为关联级别的延迟。
- 抓取策略往往会和关联级别的延迟加载一起使用,优化语句。
2、抓取策略
1、抓取策略的概述
通过一个对象抓取到关联对象需要发送SQL语句,SQL语句如何发,发送什么样的格式通过策略进行配置。
- 通过<set>或者<many-to-one>上通过fetch属性进行设置。
- fetch和这些标签上的lazy如何设置优化发送的SQL语句。
2、<set>上的fetch和lazy
-
fetch:抓取策略,控制SQL语句格式。取值有:
- select:默认值,发送普通的select语句,查询关联对象
- join:发送一条迫切左外连接查询关联对象
- subselect:发送一条子查询查询其关联对象
-
lazy:延迟加载,控制查询关联对象的时候是否采用延迟。取值有:
- true:默认值,查询关联对象的时候,采用延迟加载
- false:查询关联对象的时候,不采用延迟加载
- extra:及其懒惰。(用什么发送什么)
注意:在实际开发过程中,一般采用默认值。如果有特殊的需求,可能需要配置join。
测试:
3. 默认情况下,发送SQL语句:
默认情况,即配置fetch=“select” lazy="true"
@Test
// 默认情况,即配置 fetch="select" lazy="true"
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询客户的SQL
System.out.println(customer);
// 查看1号客户的每个联系人的信息
for (LinkMan linkMan : customer.getLinkMans()) { // 发送一条根据ID查询联系人的SQL
System.out.println(linkMan.getLkm_name());
}
transaction.commit();
}
- 配置fetch=“select” lazy="false"
@Test
// 配置fetch="select" lazy="false"
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送两条SQL语句:查询客户,查询客户关联的联系人
System.out.println(customer);
// 查看1号客户的每个联系人的信息
/*for (LinkMan linkMan : customer.getLinkMans()) {
System.out.println(linkMan.getLkm_name());
}*/
System.out.println(customer.getLinkMans().size());
transaction.commit();
}
- 配置fetch=“select” lazy="extra"
@Test
// 配置fetch="select" lazy="extra"
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条查询1号客户的SQL语句
System.out.println(customer);
// 查看1号客户的每个联系人的信息
/*for (LinkMan linkMan : customer.getLinkMans()) {
System.out.println(linkMan.getLkm_name());
}*/
System.out.println(customer.getLinkMans().size()); // 发送一条select count() from.....
transaction.commit();
}
- 配置fetch=“join” lazy=失效
@Test
// 配置fetch="join" lazy=失效
public void demo5(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
//查询1号客户
Customer customer = session.get(Customer.class, 1l);// 发送一条迫切左外连接查询记录
System.out.println(customer);
System.out.println(customer.getLinkMans().size()); // 不发送
transaction.commit();
}
- 配置fetch=“subselect” lazy="true"
@Test
// 配置fetch="subselect" lazy="true"
public void demo6(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL
for (Customer customer : list) {
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());// 发送一条子查询
}
transaction.commit();
}
注意:在设置为subselect下,不能只查询一条记录,否则看不到子查询。
- 配置fetch=“subselect” lazy="false"
@Test
// 配置fetch="subselect" lazy="false"
public void demo7(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<Customer> list = session.createQuery("from Customer").list();// 发送查询所有客户的SQL和一条子查询
for (Customer customer : list) {
System.out.println(customer.getCust_name());
System.out.println(customer.getLinkMans().size());
}
transaction.commit();
}
- 配置fetch=“subselect” lazy="extra"
在统计个数的时候才会发送统计的SQL语句。
3、<many-to-one>标签上的fetch和lazy
-
fetch:抓取策略,控制SQL语句格式。取值有:
- select:默认值,发送普通的select语句,查询关联对象
- join:发送一条迫切左外连接查询关联对象
-
lazy:延迟加载,控制查询关联对象的时候是否采用延迟。取值有:
- proxy:默认值,proxy具体取值,取决于另一端的<class>上的lazy的值
- false:查询关联对象的时候,不采用延迟加载
- no-proxy(不会使用)
注意:在实际开发过程中,一般采用默认值。如果有特殊的需求,可能需要配置join。
测试:
3. 默认情况,配置fetch=“select”,lazy=“proxy”
@Test
/*
* 默认值:配置fetch="select",lazy="proxy"
*/
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条查询联系人的语句
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());// 发送一条select语句查询联系人所关联的客户
transaction.commit();
}
- 配置fetch=“select” lazy=“false”
@Test
/**
* fetch="select" lazy="false"
*/
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条查询联系人的语句,发送一条select语句查询
// 联系人所关联的客户
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());
transaction.commit();
}
- 配置fetch=“join” lazy=失效
@Test
/**
* fetch="join" lazy=失效
*/
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
LinkMan linkMan = session.get(LinkMan.class, 1l);// 发送一条迫切左外连接查询联系人所关联的客户
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());
transaction.commit();
}
3、批量抓取
1、什么是批量抓取:一批关联对象一起抓取,batch-size
2、测试批量抓取
- 获取客户的时候,批量获取联系人
在Customer.hbm.xml的set标签下,配置batch-size=“数字”,数字根据要抓取的联系人的数量确定。
@Test
// 获取客户的时候,批量获取联系人
// 在Customer.hbm.xml中的set标签上配置batch-size
public void demo1() {
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();
}
- 获取联系人的时候,批量获取客户。
在Customer.hbm.xml的class标签下,配置batch-size=“数字”,数字根据要抓取的联系人的数量确定。
@Test
// 获取联系人的时候,批量获取客户
// 在Customer.hnm.xml的class标签上配置batch-size
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
List<LinkMan> list = session.createQuery("from LinkMan").list();
for (LinkMan linkMan : list) {
System.out.println(linkMan.getLkm_name());
System.out.println(linkMan.getCustomer().getCust_name());
}
transaction.commit();
}