Hibernate的查询方式

发布于 2020-03-15  233 热度


五种查询方式

  1. OID(Object Identifier)查询
  2. 对象导航查询
  3. HQL(Hibernate Query Language)
  4. QBC(Query By Criteria)
  5. SQL(Structured Query Language)

OID(Object Identifier)查询

使用Session的get和load方法根据OID进行简单查询。

get

立即加载:get方法执行时会立刻发送SQL,查询出对象。

//立即查询出结果赋值给customer,如果不存在则赋值null。
Customer customer = session.get(Customer.class,1l);

load

延迟加载:先创建代理对象,当用到对象时才会查询加载。

//创建代理对象
Customer customer = session.load(Customer.class,1l);

//用到了customer,才会进行查询。
//如果查找对象不存在会抛异常
System.out.println(customer);

如有特殊需求,可以通过下面的方法优化查询策略。
但是一般情况可以忽略加载策略配置。使用默认方式即可。

类级别加载策略

默认情况下load方法执行时不会发送SQL语句,而是生成一个代理对象,等待用到查询的对象时才会发送SQL进行查询。这种查询方式叫延迟加载。
* 延迟加载可以调高效率,降低压力,建议使用。
* 但是一定要确保使用时对应的session对象未关闭。

延迟加载的使用:

//执行此句不会发送SQL。获取到的customer是一个代理对象。
//实际上并没有查询出customer的信息
Session session = HibernateUnits.openSession();
Transaction tx = session.beginTransaction();
Customer customer1 = session.load(Customer.class,1);
Customer customer2 = session.load(Customer.class,1);

//使用customer1时,代理对象发现所需信息还没查询出来。
//才会依据当前session发送SQL查询出结果。
System.out.println(customer1);
tx.commit();
session.close();//关闭了session

//customer2是代理对象,需要依赖session查询出customer2的信息
//由于session已经关闭,因此执行会报找不到session的错误。
System.out.println(customer2);

可以通过修改要查询对象的映射配置文件来决定是否让load延迟加载。
class标签的lazy属性决定是否类延迟加载,其取值有两个:

  • true:默认,延迟加载
  • false:立即加载
<!--lazy:true or false-->
<class name="Customer" table="cst_customer" lazy="false" >
    <id name="cust_id">
        <generator class="native"></generator>
    </id>
</class>

对象导航查询

通过已有对象获取其属性。

Customer customer = session.get(Customer.class,1);
Set<LinkMan> linkMens = customer.getLinkMens();

如有特殊需求,可以通过下面的方法优化查询策略。
但是一般情况可以忽略加载策略配置。使用默认方式即可。

关联级别加载策略

关联级别加载策略是指加载一个类的时候,如何去加载其关联的对象。

集合策略 set

例如一个customer对象中有一个Set linkMens对象集合,在查询customer时是否如何去查询linkMens。
可以通过修改要查询对象的映射配置文件来决定linkMens的加载时机和加载方式。

lazy属性决定是否类延迟加载,其取值有三个:

  • true:默认,延迟加载,使用时才会加载集合数据
    使用时才会查询linkMens。

    • 延迟加载可以调高效率,降低压力,建议使用。
    • 但是一定要确保使用时对应的session对象未关闭。
  • false:立即加载
    查询customer的同时会把linkMens查询出来。
  • extra:极其懒惰
    用什么查什么,不会把所有查出来。
    例如,执行customer.getLinkMens().size(),只会发送一条查总记录数的SQL,不会查询出linkMan的其他数据。

fetch属性决定使用什么样的SQL来加载集合,其取值有三个:

  • select:默认,单表查询
  • join:多表查询
    查询customer时会使用一条多表查询语句把linkMens也查询出来。
    因此,如果fetch="join",会忽略掉lazy属性。
  • subselect:子查询

batch-size属性决定每次查询出多少条

映射文件配置:

<class name="Customer" table="cst_customer">
    <id name="cust_id">
        <generator class="native"></generator>
    </id>
    <!--
        lazy:true or false or extra
        fetch:select or join or subselect
    -->
    <set name="linkMens" lazy="extra" fetch="select" batch-size="3">
        <key column="lkm_cust_id"></key>
        <one-to-many class="LinkMan"/>
    </set>
</class>

对象策略 many-to-one

例如一个linkMan对象中关联一个customer对象。
可以通过修改要查询对象的映射配置文件来决定customer的加载时机和加载方式。

lazy属性决定是否类延迟加载,其取值有三个:

  • proxy:默认,代理,由Customer类级别加载策略决定
  • no-proxy:延迟加载,使用时才会加载集合数据
    使用时才会查询customer。
  • false:立即加载
    查询linkMan的同时会把customer查询出来。

fetch属性决定使用什么样的SQL来加载集合,其取值有三个:

  • select:默认,单表查询
  • join:多表查询
    查询linkMan时会使用一条多表查询语句把customer也查询出来。
    因此,如果fetch="join",会忽略掉lazy属性。

映射文件配置:

<class name="LinkMan" table="cst_linkman" >
    <id name="lkm_id"  >
        <generator class="native"></generator>
    </id>
    <many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="join" lazy="proxy"  >
    </many-to-one>
</class>

HQL(Hibernate Query Language)

HQL类似于SQL,但是SQL是面向数据库表查询,HQL是面向对象查询。
Hibernate提供了Query接口,它是Hibernate提供的专门的HQL查询接口,能够执行各种复杂的HQL查询语句。
它具有以下功能:
1)在查询语句中设定各种查询条件
2)支持投影查询,即仅检索出对象的部分属性
3)支持分页查询
4)支持连接查询
5)支持分组查询,允许使用having和group by关键字
6)提供内置聚集函数,如sum()、min()和max()
7)能够调用用户定义的SQL函数
8)支持子查询,即嵌入式查询
9)支持动态绑定参数

直接查

String hql1 = " from  cn.itcast.domain.Customer ";//查询Customer的所有对象,完整写法
String hql2 = "from  Customer"; //简单写法
String hql3 = " from java.lang.Object";//这样会查询出所有对象
Query query = session.createQuery(hql1);
List list = query.list();//把对象列表存在list里

排序 order by

String hql1 = " from  cn.itcast.domain.Customer order by cust_id asc ";//升序
String hql2 = " from  cn.itcast.domain.Customer order by cust_id desc ";//降序
Query query = session.createQuery(hql1);
List list = query.list();//把对象列表存在list里

条件 where

用 ? 表示占位符

String hql1 = " from  cn.itcast.domain.Customer where cust_id =? ";//用 ? 表示占位符
Query query = session.createQuery(hql1);
query.setParameter(0, 2l);//把下标为0的?替换为2l
List list = query.list();//把对象列表存在list里

用 :名称 表示占位符

String hql1 = " from  cn.itcast.domain.Customer where cust_id = :id ";//
Query query = session.createQuery(hql1);
query.setParameter("id", 2l);//把名为id的占位符替换为2l
List list = query.list();//把对象列表存在list里

分页

相当于SQL的limit

String hql1 = " from  cn.itcast.domain.Customer  ";//完整写法
Query query = session.createQuery(hql1);
query.setFirstResult(0);//从第几条开始
query.setMaxResults(2);//获取多少条

List list = query.list();

聚合函数

和SQL的聚合函数差不多

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();

投影查询

String hql1 = "select cust_name from  cn.itcast.domain.Customer";//只查cust_name一列
String hql2 = "select cust_name,cust_id from cn.itcast.domain.Customer";//查两列
String hql3 = "select new Customer(cust_id,cust_name) from Customer";//查两列并封装成对象

Query query = session.createQuery(hql3);
List list = query.list();

连接查询

内连接 inner join

将连接的两端对象分别返回.放到数组中。

String hql = " from Customer c inner join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();

迫切内连接

帮我们进行封装.返回值就是一个对象。

String hql = " from Customer c inner join fetch c.linkMens ";
Query query = session.createQuery(hql);
List<Customer> list = query.list();

左外连接

String hql = " from Customer c left join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();

右外连接

String hql = " from Customer c right join c.linkMens ";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();

QBC(Query By Criteria)

直接查

Criteria c = session.createCriteria(Customer.class);
List<Customer> list = c.list();

条件

HQL符号与Restrictions对象的方法对应关系:

符号 方法名 全拼
> gt Greater Than
>= ge Greater than or Equal
< lt Less Than
<= le Less than or Equal
== eq EQual
!= ne Not Equal
in in
between and between
like like
is not null isNotNull
is null isNull
or or
and and
Criteria c = session.createCriteria(Customer.class);
//c.add(Restrictions.idEq(2l));根据主键查
c.add(Restrictions.eq("cust_id",2l));//cust_id==2l
c.add(
    Restrictions.or(
        Restrictions.in("cust_name","咔嚓小窝"),
        Restrictions.or(Restrictions.idEq(3),Restrictions.idEq(4))
    )
);//多个条件
List<Customer> list = c.list();

分页

与HQL一样

Criteria c = session.createCriteria(Customer.class);
//limit ?,? 
c.setFirstResult(0);//从第几条开始
c.setMaxResults(2);//获取多少条

List<Customer> list = c.list();

排序

Criteria c = session.createCriteria(Customer.class);

c.addOrder(Order.asc("cust_id"));//升序
//c.addOrder(Order.desc("cust_id"));//降序

List<Customer> list = c.list();

聚合

Criteria c = session.createCriteria(Customer.class);

//设置查询目标
c.setProjection(Projections.rowCount());//总记录数
c.setProjection(Projections.count("cust_name"));//计数
c.setProjection(Projections.sum("cust_id"));//合计
c.setProjection(Projections.avg("cust_id"));//平均值
c.setProjection(Projections.max("cust_id"));//最大值
c.setProjection(Projections.min("cust_id"));//最小值
//Projections还有很多方法,在此略过
List list = c.list();

离线查询对象

为了增加Dao层方法的重用性,可以在Dao层以外封装好离线查询对象(DetachedCriteria),然后把离线查询对象传给Dao层进行查询。

Dao层以外:

DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);//生成离线查询对象
dc.add(Restrictions.idEq(6l));//添加查询条件
xxxx.search(dc);//调用下一层

Dao层

Criteria c = dc.getExecutableCriteria(session);
List list = c.list();

我一直在开辟我的天空