Hibernate快速笔记2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_28666193/article/details/85329642

上篇:Hibernate快速笔记1

1.Hibernate的查询方式
2.Hibernate的抓取策略

Hibernate查询方式

  1. OID检索:根据ID查询对象,Get/Load方法

    session.get(Customer.class1L)
    session.load(Customer.class, 2L)
    
  2. 对象导航检索:根据已查询对象,获得其关联对象,例如用户和角色

    Customer cus = session.get(Customer.class1L)
    LinkMan lkm = cus.getLinkMan()
    
  3. HQL检索:使用HQL语句,进行查询;Hibernate Query Language,面向对象的查询

    • 简单查询

      Query query = session.createQuery("from Customer"); //查询的是类,不是表
          List<Customer> list = query.list();             //list 链式显示获取
          for (Customer customer : list) {
              System.out.println(customer);
          }
      //支持别名,不支持select *
      session.createQuery("select c from Customer c")
      
    • 排序查询:支持Order by 属性名,默认升序

      List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
      
    • 条件查询:1.按位置绑定; 2.按类型绑定

      //1.按位置绑定
      Query query = session.createQuery("from Customer where cust_id = ? and cust_name like ?");
      query.setParameter(0, 1L);
      query.setParameter(1, "c%");
      List<Customer> list = query.list();
      //2.按名称绑定
      //冒号后必须紧跟名字,名字可以任意取定
      Query query2 = session.createQuery("from Customer where cust_id = :id and cust_name like :name");
      query2.setParameter("id", 2L);
      query2.setParameter("name", "c%");
      List<Customer> list2 = query2.list();
      
    • 投影查询:查询某些列或某些字段的行

      //单个属性,返回的Object
      Query query = session.createQuery("select c.cust_name from Customer c");
      List<Object> list = query.list();
      for (Object object : list) {
          System.out.println(object);
      }
      //多个列,Object数组
      Query query2 = session.createQuery("select c.cust_id, c.cust_name from Customer c");
      List<Object[]> list2 = query2.list();
      for (Object[] objects : list2) {
          System.out.println(Arrays.toString(objects));
      }
      //多列,封装成对象
      Query query3 = session.createQuery("select new Customer(c.cust_id, c.cust_name) from Customer c");
      List<Customer> list3 = query3.list();
      
    • 分页查询

      Query query = session.createQuery("from LinkMan");
      query.setFirstResult(10);   //limit ?,?
      query.setMaxResults(10);
      
    • 分组统计查询

      //count,max,min,avg等
      Query query = session.createQuery("select min(cust_id) from Customer");
      Object result = query.uniqueResult();
      System.out.println(result);   //也可以使用list,输出第一个元素
      //分组-----注意:lkm_cust_id不是LinkMan的属性,所以选择不了
      Query query2 = session.createQuery("select customer, count(*) from LinkMan 		group by lkm_cust_id having count(*) > 1");
      List<Object[]> list = query2.list();
      for (Object[] objects : list) {
          System.out.println(Arrays.toString(objects));
      }
      
  4. QBC检索:query by criteria,适合多条件查询

    • 简单查询

      //使用criteria
      Criteria criteria = session.createCriteria(Customer.class);
      List<Customer> list = criteria.list();
      for (Customer customer : list) {
      	System.out.println(customer);
      }	
      
      //使用criteria ,默认升序
      Criteria criteria = session.createCriteria(Customer.class);
      criteria.addOrder(Order.desc("cust_id"));  //Order为Hibernate对象
      List<Customer> list = criteria.list();
      
    • 条件查询:add,添加普通条件;addOrder,添加顺序;setProjection,添加聚合函数等

      //条件查询
          Session session = HibernateUtils.getCurrentSession();
          Transaction transaction = session.beginTransaction();
          //条件默认是与,可以改成or
          Criteria criteria = session.createCriteria(Customer.class);
          // eq = ; lt <; gt >; like,and,or,in,between
      //		criteria.add(Restrictions.eq("cust_name", "cus3"));		
      //		criteria.add(Restrictions.le("cust_id", 2L));
      
          //or,两个条件
          //criteria.add(Restrictions.or(Restrictions.eq("cust_name", "cus3"), Restrictions.le("cust_id", 2L)));
          //or多个条件----可以使用between或者in
          Disjunction disjunction = Restrictions.disjunction();
          disjunction.add(Restrictions.eq("cust_name", "cus3"));
          disjunction.add(Restrictions.eq("cust_name", "cus1"));
          disjunction.add(Restrictions.eq("cust_name", "cus1"));
          criteria.add(disjunction);		
      
          List<Customer> list = criteria.list();
      
    • 分页查询

          Criteria criteria = session.createCriteria(Customer.class);
          criteria.setFirstResult(1);
          criteria.setMaxResults(1);
      
          List<Customer> list = criteria.list();
      
    • 分组统计查询

      Criteria criteria = session.createCriteria(Customer.class);
      criteria.setProjection(Projections.rowCount());
      //Projections.max,min,avg等,还有having,group by等
      Long num = (Long) criteria.uniqueResult();	
      System.out.println(num);
      
  5. QBC离线检索: 适用于多表、多条件和分页的查询情况,一般在SSH模型中使用的到

    离线:DetachedCriteria,脱离session使用;方便在条件查询时,减轻了JDBC中的参数查询语句的匹配重复性问题。可以用来在Web层直接操作,不需要在DAO中判断

    //Web层的操作
        DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
        dc.add(Restrictions.like("cust_name", "cus%"));
    
        //到Service绑定session
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        //执行
        Criteria criteria = dc.getExecutableCriteria(session);
        List<Customer> list = criteria.list();
        for (Customer customer : list) {
            System.out.println(customer);
        }
    
  6. HQL的多表查询:QBC也可以,支持功能一般

    a) SQL的多表查询方式:连接查询和子查询

    • 连接查询:

      • 交叉查询——不常用,笛卡尔积

      • 内连接;查询的结果是两个表的交集,inner可以省略

        select * from A,B where A.id = B.id 隐式

        select * from A inner join B on A.id = B.id 显式

      • 外链接:查询结果是某个表与两个表的交集的并集

        • 左外连接:左表的全部和两个表的交集,许多右边字段为空的结果
        • 右外连接:右表的全部和两个表的交集,许多左边字段为空的结果
    • 子查询:多表嵌套查询,相关子查询,非相关子查询

    b) HQL的多表查询:

    • 连接查询

      • 交叉连接
      • 内连接:显式、隐式、迫切
      • 外链接:左外、右外、迫切左外
    • 普通内连接和迫切内连接只有一个关键字fetch不同,其发送的SQL语句和查询的结果集都是一样的,fetch是Hibernate的内容,主要用来将返回结果自动封装成对象;在普通内连接中,会将连接查询的每一条结果分成两个对象来封装(下面示例代码中,能看见普通的内连接会查询两个表),而迫切内连接会将相同的封装到一个对象中。

      普通查询:
      Transaction transaction = session.beginTransaction();
      //SQL的内连接:SELECT * from cst_customer inner join cst_linkman on cst_customer.cust_id = cst_linkman.lkm_cust_id;
      //HQL只需关联类中对于外键的集合即可
      //查询结果会匹配到对应的集合中,若去重加上distinct即可
      Query query = session.createQuery("from Customer c inner join c.linkMans");
      List<Object[]> list = query.list();
      for (Object[] objects : list) {
          System.out.println(Arrays.toString(objects));
      }
      

      在console中能看见:

      Hibernate: 
          select
              customer0_.cust_id as cust_id1_0_0_,
              linkmans1_.lkm_id as lkm_id1_1_1_,
              customer0_.cust_name as cust_nam2_0_0_,
              customer0_.cust_source as cust_sou3_0_0_,
              customer0_.cust_industry as cust_ind4_0_0_,
              customer0_.cust_level as cust_lev5_0_0_,
              customer0_.cust_phone as cust_pho6_0_0_,
              customer0_.cust_mobile as cust_mob7_0_0_,
              linkmans1_.lkm_name as lkm_name2_1_1_,
              linkmans1_.lkm_gender as lkm_gend3_1_1_,
              linkmans1_.lkm_phone as lkm_phon4_1_1_,
              linkmans1_.lkm_mobile as lkm_mobi5_1_1_,
              linkmans1_.lkm_email as lkm_emai6_1_1_,
              linkmans1_.lkm_qq as lkm_qq7_1_1_,
              linkmans1_.lkm_position as lkm_posi8_1_1_,
              linkmans1_.lkm_memo as lkm_memo9_1_1_,
              linkmans1_.lkm_cust_id as lkm_cus10_1_1_ 
          from
              cst_customer customer0_ 
          inner join
              cst_linkman linkmans1_ 
                  on customer0_.cust_id=linkmans1_.lkm_cust_id
      
      [Customer [cust_id=1, ...]
      [Customer [cust_id=1, ..., linkMans=[LinkMan [...l]
      ...  //30 行
      
    • 若使用迫切的内连接查询,则会返回直接封装好的结果

      //迫切内连接
      Query query = session.createQuery("from Customer c inner join fetch c.linkMans");
      List<Customer> list = query.list();  //能直接获取到Customer的对象
      for (Customer customer : list) {
          System.out.println(customer);
      }
      

      我们在console能看到的信息(若想要看到属性集合,在tostring函数中添加,否则不会出现linkman)

      Hibernate: 
          select
              customer0_.cust_id as cust_id1_0_0_,
              linkmans1_.lkm_id as lkm_id1_1_1_,
              customer0_.cust_name as cust_nam2_0_0_,
              customer0_.cust_source as cust_sou3_0_0_,
              customer0_.cust_industry as cust_ind4_0_0_,
              customer0_.cust_level as cust_lev5_0_0_,
              customer0_.cust_phone as cust_pho6_0_0_,
              customer0_.cust_mobile as cust_mob7_0_0_,
              linkmans1_.lkm_name as lkm_name2_1_1_,
              linkmans1_.lkm_gender as lkm_gend3_1_1_,
              linkmans1_.lkm_phone as lkm_phon4_1_1_,
              linkmans1_.lkm_mobile as lkm_mobi5_1_1_,
              linkmans1_.lkm_email as lkm_emai6_1_1_,
              linkmans1_.lkm_qq as lkm_qq7_1_1_,
              linkmans1_.lkm_position as lkm_posi8_1_1_,
              linkmans1_.lkm_memo as lkm_memo9_1_1_,
              linkmans1_.lkm_cust_id as lkm_cus10_1_1_,
              linkmans1_.lkm_cust_id as lkm_cus10_1_0__,
              linkmans1_.lkm_id as lkm_id1_1_0__ 
          from
              cst_customer customer0_ 
          inner join
              cst_linkman linkmans1_ 
                  on customer0_.cust_id=linkmans1_.lkm_cust_id
      Customer [cust_id=1, ..., linkMans=[LinkMan [...]]
      Customer [cust_id=1, ..., linkMans=[LinkMan [...]]
      ...
      //30行全部的查询结果
                
      //使用distinct的结果,只有三行
      
      
  7. SQL查询

    //SQL查询
        SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
        List<Object[]> list = sqlQuery.list();
    
    //		for (Object[] objects : list) {
    //			System.out.println(Arrays.toString(objects));
    //		}
        //绑定到类---封装
        sqlQuery.addEntity(Customer.class);
        List<Customer> list2 = sqlQuery.list();
        for (Customer customer : list2) {
            System.out.println(customer);
        }
    

Hibernate抓取策略

Hibernate提供了一系列的优化方式,来提高封装性带来的性能问题,尤其在获取关联对象的时候。例如一级二级缓存(二级一般被Redis替代)机制、和抓取策略等,都是一些用来优化的手段。抓取策略主要是对查询时的语句等做的优化处理。

优化的方式:1)缓存怎么处理;2)查询的优化(抓取)

  1. 延迟加载:懒加载,执行语句的时候,不直接查询;当使用到关联的对象才发送查询语句。

    • 类级别的延迟加载:如load方法,可以在xml的class配置文件中的lazy = ‘true’(默认),若配置为false则load方法也是直接加载,不使用延迟加载。

      <class name="com.leehao.hibernateLearning2.domain.Customer" table="cst_customer" lazy="true">
      
      • 类级别延迟加载通过<class>上的lazy进行配置,如果让lazy失效

        • 将lazy设置为false

        • 将持久化类使用final修饰

        • Hibernate. Initialize()

    • 关联级别的延迟加载:查询某个对象,获取对象的关联对象时。抓取策略往往会和关联级别的延迟加载一起使用,优化语句。

  2. 抓取策略:通过类加载其关联对象时,需要发送SQL语句,如何发送、什么时候发送,与设置的抓取策略有关。可以通过在<set>和<many-to-one>标签上的fetch属性来设置。fetch 属性和lazy属性一起使用。

<Set>上的fetch和lazy抓取
  1. Fetch控制抓取策略,控制的是发送的SQL语句的格式

    • select:默认,发送普通的select语句,来查询关联对象;如根据Customer来查询联系人,会发送多次SQL,每一个对象会查一次————可以使用批量查询的设置解决
    • join:发送一条迫切的左外连接查询关联的对象,只发送一次查询SQL,这时lazy的控制没有作用
    • subselect:发送一条子查询来查询关联的对象,和select唯一的不同就是使用子查询;也是两次SQL,第二次将所有关联的东西放入一个表。“相当于”使用了一次select和一次join。
  2. lazy:延迟加载,控制查询关联对象的时候是否使用延迟

    • true:默认,使用延迟加载查询关联对象
    • false:不使用延迟加载
    • extra:“极其懒惰?”
  3. 在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join

    //关联对象的抓取策略----set中,也就是1的一方,如何查询它关联的多的一方的集合
    //默认set中,<set name="linkMans" fetch="select" lazy="true">
    Customer customer = session.get(Customer.class, 1L);
    //获取的时候才会发送SQL
    for (LinkMan linkMan : customer.getLinkMans()) {
        System.err.println(linkMan.getLkm_name());
    }
    
    -------------------------------------------------------------
    //lazy的false或者extra
    //<set name="linkMans" fetch="select" lazy="extra">
    Customer customer = session.get(Customer.class, 1L);
    //获取的时候才会发送SQL
    System.out.println(customer.getLinkMans().size());
    -------------------------------------------------------------
    /**注:使用extra时,发送的SQL语句如下
    Hibernate: 
        select
            count(lkm_id) 
        from
            cst_linkman 
        where
            lkm_cust_id =?*/
    
<many-to-one>上的fetch和lazy抓取
  1. fetch

    • select:默认
    • join:迫切的左外连接,此时lazy失效
  2. lazy

    • proxy:默认,proxy具体的取值,取决于另一端的<class>上的lazy的值
    • false
    • no-proxy:不使用
  3. 在实际开发中,一般都采用默认值。如果有特殊的需求,可能需要配置join

    //<many-to-one name="customer" fetch="select" lazy="proxy"  class=...
        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());
    
批量抓取

获取多个用户的多个联系人的信息,可以想象成抓取两个表的内连接的结果。

1的一方中,在Set中配置batch-size=“n”即可,表示每次抓取n个,默认是1;反之,如果使用如LinkMan批量查询Customer,则需要在Customer中的class配置。

//<set name="linkMans" batch-size="3">
		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());
			}
		}
---------------------------------------------------------
Hibernate: 
    select
        customer0_.cust_id as cust_id1_0_,
        customer0_.cust_name as cust_nam2_0_,
        customer0_.cust_source as cust_sou3_0_,
        customer0_.cust_industry as cust_ind4_0_,
        customer0_.cust_level as cust_lev5_0_,
        customer0_.cust_phone as cust_pho6_0_,
        customer0_.cust_mobile as cust_mob7_0_ 
    from
        cst_customer customer0_
cus1
Hibernate: 
    select
        linkmans0_.lkm_cust_id as lkm_cus10_1_1_,
        linkmans0_.lkm_id as lkm_id1_1_1_,
        linkmans0_.lkm_id as lkm_id1_1_0_,
        linkmans0_.lkm_name as lkm_name2_1_0_,
        linkmans0_.lkm_gender as lkm_gend3_1_0_,
        linkmans0_.lkm_phone as lkm_phon4_1_0_,
        linkmans0_.lkm_mobile as lkm_mobi5_1_0_,
        linkmans0_.lkm_email as lkm_emai6_1_0_,
        linkmans0_.lkm_qq as lkm_qq7_1_0_,
        linkmans0_.lkm_position as lkm_posi8_1_0_,
        linkmans0_.lkm_memo as lkm_memo9_1_0_,
        linkmans0_.lkm_cust_id as lkm_cus10_1_0_ 
    from
        cst_linkman linkmans0_ 
    where
        linkmans0_.lkm_cust_id in (
            ?, ?, ?
        )

猜你喜欢

转载自blog.csdn.net/qq_28666193/article/details/85329642