Hibernate高级

Hibernate高级

    • Hibernate的查询方式
        • OID查询
        • 对象导航检索
        • HQL单表查询(重点)
            • HQL的简单查询
            • HQL的排序查询
            • HQL的条件查询
            • HQL的投影查询
            • HQL的分组统计查询
            • HQL的分页查询
            • HQL的聚合函数查询
        • HQL的多表查询
            • 内连接
            • HQL的迫切内连接
        • QBC单表查询(重点)
            • 简单查询
            • 分页查询
            • 排序查询
            • 条件查询
            • 分组统计查询
            • 离线条件查询(重点)
        • SQL查询
    • Hibernate的抓取策略(优化)
        • 延迟加载
            • 延迟加载的分类
        • 抓取策略
            • set 标签上的fetch和lazy
            • many-to-one 标签上的fetch和lazy
        • 批量抓取

Hibernate的查询方式

OID查询

根据主键进行检索

类名 对象 = session.get(类名.class,主键(Long));
类名 对象 = session.load(类名.class,主键(Long));

对象导航检索

Hibernate根据一个已经查询到的对象,获取其关联的对象的一种查询方式

LinkMan linkMan = session.get(LinkMan.class,1L);
Customer customer = linMan.getCustomer();

HQL单表查询(重点)

Hibernate的查询语言,是一种面向对象的方式的查询语言,语法类似SQL。通过session.createQuery(),用于接收一个HQL进行查询方式

HQL的简单查询

格式: from 类名(可以全名,也可以不全名,只要映射配置好) 别名

Query query = session.createQuery("from Customer c");
List<Customer> list = query.list();
HQL的排序查询

默认升序
格式: from 类名 order by 属性名 排序规则

 Query query = session.createQuery("from Customer order by cust_id");
 List<Customer> list = query.list();
HQL的条件查询
  1. 按位置绑定参数(从0开始)
    Query query = session.createQuery("from Customer where cust_name = ? ");
    //从0开始
    query.setParameter(0,"1张三");
    List<Customer> list = query.list();
    
  2. 按名称绑定参数
    Query query = session.createQuery("from Customer where cust_name = :aaa ");
     query.setParameter("aaa","1张三");
    
HQL的投影查询
  • 查询对象的某个属性

    List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
    for (Object obj:list){
        System.out.println(obj);
    }
    
  • 查询某些属性

    List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();
    for (Object[] objs:list){
        System.out.println(Arrays.toString(objs));
    }
    
  • 将查询的某些属性装入对象中

    前提:需要在对象中为需要查询的属性添加构造方法,注意别把无参构造弄没了

    List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();
    for (Customer customer:list){
        System.out.println(customer);
    }
    
HQL的分组统计查询
List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source having count(*) >= 2").list();
for (Object[] obj:list){
   System.out.println(Arrays.toString(obj));
}
HQL的分页查询
Query query = session.createQuery("from LinkMan");
//从0开始
query.setFirstResult(0);
query.setMaxResults(10);
List<LinkMan> list = query.list();
for (LinkMan linkMan:list){
    System.out.println(linkMan);
}
HQL的聚合函数查询

sql语句的函数在HQL中都可以使用

//uniqueResult获取唯一结果
Object object = session.createQuery("select count(*) from Customer").uniqueResult();
System.out.println(object);

HQL的多表查询

内连接

原sql语句:
显示内连接:

select * from cst_customer c inner join cst_linkman l on c.cust_id = l.lkm_cust_id;

HQL的内连接:

List<Object[]> list = session.createQuery("from Customer c inner join c.linkMans").list();
for (Object[] obj:list){
    System.out.println(Arrays.toString(obj));
}
HQL的迫切内连接

HQL的普通内连接查询接收到的对象是一个数组,我们可以使用迫切内连接将查询对象封装到对象中去

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

QBC单表查询(重点)

条件查询,是一种更加面向对象化的查询方式

简单查询
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for (Customer customer:list){
    System.out.println(customer);
}

分页查询
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(0);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan:list){
    System.out.println(linkMan);
}
排序查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.desc("cust_id"));
List<Customer> list = criteria.list();
for (Customer customer:list){
    System.out.println(customer);
}
条件查询
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.or(Restrictions.like("cust_name","1张%")));
List<Customer> list = criteria.list();
for (Customer customer:list){
    System.out.println(customer);
}

分组统计查询
Criteria criteria = session.createCriteria(Customer.class);
//count(*)
criteria.setProjection(Projections.rowCount());
Object o = criteria.uniqueResult();
System.out.println(o);
离线条件查询(重点)

适用于sql条件比较多的项目,离线条件查询一般写在web层,拼接条件,然后传给service,调用dao,省去dao需要拼接许多sql的麻烦

//这下面两行代码写在web层,然后将DetachedCriteria对象传给service,调用dao
   DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);
   detachedCriteria.add(Restrictions.like("cust_name","1张%"));

//Dao代码
   Session session = HibernateUtil.getSession();
   Transaction transaction = session.beginTransaction();
   //绑定session
   Criteria criteria = detachedCriteria.getExecutableCriteria(session);
   List<Customer> list = criteria.list();
   for (Customer customer:list){
       System.out.println(customer);
   }

SQL查询

通过使用基本sql语句查询

SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] obj:list){
    System.out.println(Arrays.toString(obj));
}

将查询结果封装到对象中

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

Hibernate的抓取策略(优化)

延迟加载

延迟加载(懒加载):执行该行代码时,不会发送语句去查询,在真正使用这个对象的属性时才会去发送sql语句进行查询

延迟加载的分类
  • 类级别的延迟加载
    指的是通过load方法查询某个对象多的时候,是否采用延迟
    可以在需要查询的对象的映射配置的class标签上配置lazy属性,默认值为true,如果为false,则load方法的效果会与get方法一样

    <class name="com.hibernate.pojo.Customer" table="cst_customer" lazy="false">
    
  • 关联级别的延迟加载(重点:抓取策略往往会和关联级别的延迟加载一起使用,优化sql语句)
    指的是在查询到某个对象的时候,查询其关联的对象的时候,是否采用了延迟加载
    例如:

    Customer customer = session.get(Customer.class, 1L);
            customer.getLinkMans();//通过客户获取关联对象联系人,联系人对象是否采用了延迟加载,称为关联级别的延迟
    

抓取策略

概述:通过一个对象抓取到关联对象需要发送的sql语句,sql语句如何发送,发成什么样的格式通过策略进行配置,可以通过set或者many to one 标签上的fetch属性和lazy属性进行设置

set 标签上的fetch和lazy
  • fetch:抓取策略,控制SQL语句格式
    • select:(默认值) 发送普通的select语句,查询关联对象
    • join:发送一条迫切左外连接查询关联对象
    • subselect:发送一条子查询查询其关联对象
  • lazy:延迟加载,控制关联对象的时候是否采用延迟
    • true:(默认值) 查询关联对象的时候,延迟加载
    • false:查询关联对象的时候,不采用延迟加载
    • extra:极其懒惰
  1. 默认设置fetch=“select” lazy=“true”

    //查询1号客户
    Customer customer = session.get(Customer.class, 1L);//发送一条根据客户id查询客户信息的sql,不关联查询联系人
    //查询1号客户每个联系人的信息
    for (LinkMan linkMan:customer.getLinkMans()){//发送一条根据客户id查询联系人的sql
        System.out.println(linkMan.getLkm_name());
    }
    

    当客户需要使用关联对象的时候,他才会去查询关联对象

  2. fetch=“select” lazy=“false”

    //查询1号客户
    Customer customer = session.get(Customer.class, 1L);//发送两条sql语句根据客户id查询客户信息的sql,根据客户id查询联系人
    //查询1号客户每个联系人的信息
    for (LinkMan linkMan:customer.getLinkMans()){
        System.out.println(linkMan.getLkm_name());
    }
    

    即便不使用,他也会查询

  3. fetch=“select” lazy=“extra”

    //查询1号客户
    Customer customer = session.get(Customer.class, 1L);//发送一条根据客户id查询客户信息的sql
    System.out.println(customer.getLinkMans().size());//发送一条根据客户id查询联系人数目的sql
    

    如果用不到对象中的属性,都不会发送查询信息的sql语句

  4. fetch=“join”

    //查询1号客户
    Customer customer = session.get(Customer.class, 1L);//发送一条迫切左外连接的sql语句
    //查询1号客户每个联系人的信息
    for (LinkMan linkMan:customer.getLinkMans()){
        System.out.println(linkMan.getLkm_name());
    }
    System.out.println(customer.getLinkMans().size());
    

    如果fetch设置为join,他会发送一条迫切左外连接将客户和对应的联系人都查出来,这个时候不会发送第二条sql语句,所以lazy失效

  5. fetch=“subselect” lazy=“true”

     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());//发送一条子查询查询联系人信息
    
    }
    

    当客户需要使用关联对象的时候,他会使用子查询去查询关联对象的信息

many-to-one 标签上的fetch和lazy
  • fetch:抓取策略,控制SQL语句格式
    • select:(默认值) 发送普通的select语句,查询关联对象
    • join:发送一条迫切左外连接查询关联对象
  • lazy:延迟加载,控制关联对象的时候是否采用延迟
    • proxy:(默认值) 取决于一的一端class上的lazy属性的值
    • false:查询关联对象的时候,不采用延迟加载
效果与set标签配置的差不多,可以自己推敲

批量抓取

问题:

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

上面的代码运行后,首先会查询customer客户,然后在根据客户的id去一条一条的发送sql查询联系人,有多少客户就会发送多少sql,效率非常低
优化:
在set 标签上配置属性batch-size,一次查询多少条,就可以减少与数据库的交互

<set name="linkMans" cascade="delete,save-update" batch-size="5">
      <key column="lkm_cust_id">key>
      <one-to-many class="com.hibernate.pojo.LinkMan">one-to-many>
set>

联系人查询客户的时候也会这样,有多少联系人就会发送多少sql,可以在客户映射配置的class 标签上配置属性batch-size

你可能感兴趣的:(框架)