zoukankan      html  css  js  c++  java
  • Hibernate第四天——查询方式

    Hibernate入门最后一天第四天,我们进行查询方式的更进一步的细化:

      先看一下大致的Hibernate的提供的查询的方式:

        1.对象导航查询

        2.OID查询

        3.HQL查询

        4.QBC查询

        5.本地SQL查询

      使用框架,我们更加关注的是前四种查询的方式。

    接下来逐条介绍:

      1.对象导航查询
        例如昨天的客户联系人的一对多:
        根据id查询到客户,再根据客户下的所有联系人
        这个查询过程称为对象导航
        就是得到表示的那个set就可以
        Set<LinkMan> set = cust.getSet_LinkMan();

        /**
         * 对象导航查询(顺便OID也在里面了)
         * @author jiangbei01
         *
         */
        @Test
        public void query1(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //查询客户中的所有联系人
                Customer cust = session.get(Customer.class, 1);
                //利用对象导航查询到所有联系人
                //做法就是 得到那个表示所有联系人的set集合
                Set<LinkMan> set = cust.getSet_LinkMan();
                System.out.println(set.size());
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

      2.OID查询
        根据id查询某一条记录(返回的是对象)
        也就是session.get方法实现
        Customer cust = session.get(Customer.class, 1);

      3.HQL查询
        使用HQL语言(用到Query对象,昨天只演示了查询所有)==写语句
        HQL与SQL最大的不同是:
            HQL操作实体类
            SQL操作表

        HQL常用语句:
            查询所有 === from 实体类名称

    /**
         * HQL Query对象查询所有
         * @author jiangbei01
         *
         */
        @SuppressWarnings("deprecation")
        @Test
        public void query2(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //得到Query对象 ,显示已过时,待解决
                Query query = session.createQuery("from Customer");
                //调用方法
                List<Customer> list = query.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustLevel());
                }
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

            条件查询 === from 实体类名称 where 实体类属性=? ... 写法与SQL基本类似:

              from 实体类名称 where 属性 like ?

    /**
         * HQL条件查询 第一步都是创建query对象
         * 模糊查询极其类似,不再赘述举例这里 参数为String类型的即可(%浪%)
         */
        @Test
        public void query3(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //得到Query对象 ,显示已过时,待解决
                Query query = session.createQuery(
                        "from Customer c where c.cid=?");
                //设置条件值,也就是向?设置值,一般都是用这个方法,而较少去使用其它重载方法
                //第一个参数为int ?问号的位置,第二个为Object,这里必须注意:!!
                //pstmt里面?从1 开始 ,这里从0开始!
                query.setParameter(0, 1);
                //调用方法
                List<Customer> list = query.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustLevel());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

            
            排序查询 === from 实体类名称 order by 属性 acs

        /**
         *演示排序
         */
        @Test
        public void query4(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //得到Query对象 ,显示已过时,待解决
                Query query = session.createQuery(
                        "from Customer order by cid asc");
                //调用方法
                List<Customer> list = query.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCid());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

            分页查询 === mysql中实现分页使用的是关键字 limit,注意此时hibernate不认识Limit这个方言!

    /**
         *演示分页
         */
        @Test
        public void query5(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //得到Query对象 ,显示已过时,待解决
                Query query = session.createQuery(
                        "from Customer");
                //设置开始位置
                query.setFirstResult(0);
                //设置每页的记录数
                query.setMaxResults(5);
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

            使用的是query的封装的两个方法:
            投影查询 === (用的不是很多,原因是查到所有后部分也简单)
            投影的概念:查的是部分字段 例如 SELECT cid FROM t_stu
            HQL与SQL这里也是极其相似
              select 属性名1,属性名2 from 实体类名称(注意不能 写* ,写*查询所有应直接 from ...)
            聚合函数 === 常用的COUNT() SUM() MAX/MIN() AVG()
      HQL写法:
          select count(*) from 实体类名称
        使用这种接收只有某个的结果
          Object o = query.uniqueResult();
          注意此处返回值不能直接强转成int,因为此处o是long类型
          应当先转成long类型,再转
          Long不能直接强转,而是使用intValue()返回基本类型的值

    /**
         *演示聚合函数
         */
        @Test
        public void query6(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //得到Query对象 ,显示已过时,待解决
                Query query = session.createQuery(
                        "select count(*) from Customer");
                //只返回某个值,而不用list
                Object o = query.uniqueResult();
                System.out.println(o);
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }
    }

      

      4.QBC查询 (实际开发更倾向于此而少写HQL)
        用到的是 Criteria对象 ==不写语句,这是与HQL不同的部分,而是使用方法操作实体类进行的操作
      包含的也是这些:
        查询所有:
          得到对象,调用方法即可

    /**
         *演示QBC查询所有
         */
        @Test
        public void query6(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建对象 ,显示已过时,待解决
                Criteria criteria = session.createCriteria(Customer.class);
                //调用方法实现
                List<Customer> list = criteria.list();
                //遍历结果集
                for (Customer customer : list) {
                    System.out.println(customer.getCustName());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

        条件查询:
          通过方法控制条件

        /**
         *演示QBC条件查询
         */
        @Test
        public void query5(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建对象 ,显示已过时,待解决
                Criteria criteria = session.createCriteria(Customer.class);
                //使用add()方法设置条件的值,更多请百度Restrictions静态类的用法
                criteria.add(Restrictions.eq("cid", 1));
                List<Customer> list = criteria.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustName());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }


      以下概念不再赘述,直接见案例
        排序查询:

    /**
         *演示QBC排序查询
         */
        @Test
        public void query4(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建对象 ,显示已过时,待解决
                Criteria criteria = session.createCriteria(Customer.class);
                //设置对哪个属性进行排序,包括排序方式和排序规则(似乎不如HQL方便)
                criteria.addOrder(Order.desc("cid"));
                
                List<Customer> list = criteria.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustName());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

        分页查询:

        /**
         *演示QBC分页查询
         */
        @Test
        public void query3(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建对象 ,显示已过时,待解决
                Criteria criteria = session.createCriteria(Customer.class);
                //也是调方法,和HQL有点相似,设置分页的两个数据,注意:凡是设置的方法,一般都是先打set前缀
                criteria.setFirstResult(0);
                criteria.setMaxResults(2);
                
                List<Customer> list = criteria.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustName());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

        统计查询:
    ,  统计记录条数等:

    /**
         *演示QBC统计查询
         */
        @Test
        public void query2(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建对象 ,显示已过时,待解决
                Criteria criteria = session.createCriteria(Customer.class);
                //设置操作,其它操作举一反三
                criteria.setProjection(Projections.rowCount());
                //调用方法
                Object o = criteria.uniqueResult();
                Long l = (Long) o;
                int r = l.intValue();
                
                System.out.println(r);
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

    离线查询:
      步骤:
        创建对象
        设置操作
        调用方法
        离线查询:
      之前的criteria是通过session查询的,是依赖session的
      场景例子:希望在条件查询时就在servlet中实现条件的拼接
      就是可以离线的操作

    /**
         *演示QBC离线查询
         */
        @Test
        public void query1(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //创建离线
                DetachedCriteria detachedCriteria = DetachedCriteria
                        .forClass(Customer.class);
                //最终执行的时候才用session
                Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                
                //再执行
                List<Customer> list = criteria.list();
                for (Customer customer : list) {
                    System.out.println(customer.getCustPhone());
                }
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }


      5.本地SQL查询
        SQLQuery对象,使用本地SQL查询(前面有类似的案例,用的少的不再赘述)

        当然,这里重点应该关注前4种查询方式

      使用了上面的单表查询后,来看看HQL如何进行多表查询

        HQL多表查询(达到会用的水平先)
          回顾mysql的一般多表查询:
                内连接 INNER JOIN ON
                左外连接 LEFT OUTER JOIN ON
                右外连接 RIGHT OUTER JOIN ON
        HQL实现多表查询:
          1.内连接
          2.左外连接
          3.右外连接
          4.迫切内连接
          5.迫切左外连接(没有右外!勿擅自创造)

      再次强调,HQL操作的是实体类,而不是表!

        1.HQL内连接:
          from Customer c inner join c.set_LinkMan
          注意点:join后加的是表示联系人的set集合,并且后面没有on!

    /**
         *演示HQL内连接
         */
        @Test
        public void query1(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                
                //HQL使用的是Query对象
                Query query = session.createQuery("from Customer c inner join c.set_LinkMan");
                List list = query.list();
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

      2.迫切内连接和内连接的底层实现是一样的
        迫切内连接返回的list每部分是对象
        而内连接返回的list每部分是数组
        from Customer c inner join fetch c.set_LinkMan

      3.左外连接与迫切左外连接:
        from Customer c left outer join c.set_LinkMan
        from Customer c left outer join fetch c.set_LinkMan
        同样的,左外连接返回的每部分是数组
        迫切左外连接返回的是对象

    迫切与普通连接查询的区别:

     我们可以看到采用左外连接查询返回的结果集中包含的是对象数组,对象数组中的每个元素存放了一对相互关联的Customer对象和Order对象,
    而迫切左外连接会返回Customer对象,与Customer对象相关联的Order对象存放在Customer对象的集合元素对象中,
    这就是迫切左外连接和左外连接查询的其中一个区别(这两种检索生成的SQL语句是一样的) 

    以上两种用法与1都相差无几。

    Hibernate检索策略:
      主要分为两类:
        立即检索:
          一调用get()方法马上发送SQL语句去查询
        延迟检索:
          调用load()方法,不会马上发送语句,
      只有得到对象里面的值的时候,也就是什么时候用那个值
      才发送语句,查询数据库,调用load()时,初始里面只有传入的id值
      验证的方式是debug看发送语句的时机(F6一步一步走)


      延迟查询中又分两类:(默认会有相关的延迟优化方式,自己修改的机会少)
      类级别的延迟:
        返回一个实体类的对象
      在class标签上设置lazy值(选值见下)

      关联级别的延迟:
        查询某个客户,再查询客户里的所有联系人,
        查询客户所有联系人的过程是否需要延迟
          关联级别的延迟方式也可以自己修改(当然,默认的优化已经可以,作了解)
          修改方式是在映射文件中进行配置
          根据客户得到联系人,则配置客户的映射文件
          在set标签上设置属性:
      fetch:值select(默认)
      lazy:值true 延迟(默认)
          false 不延迟(遇到要用时都查出来给你)
          extra 极其延迟(要什么给的什么,用size就只发送count(*))

    /**
         *演示立即查询与延迟查询
         */
        @Test
        public void query1(){
            //注意规范写法
            SessionFactory sessionFactory = null;
            Session session = null;
            Transaction tx = null;
            
            try{
                //得到工厂
                sessionFactory = HibernateUtils.getSessionFactory();
                //得到session
                session = sessionFactory.openSession();
                //开启事务
                tx = session.beginTransaction();
                //一调用get方法,马上去查询
                Customer cust = session.get(Customer.class, 1);
                System.out.println(cust.getCustName());
                
                
                Customer cust1 = session.load(Customer.class, 2);//此时Customer中只有一个id值
                System.out.println(cust1.getCustName());//去拿它的名字时才发语句去查询
                 
                
                //提交事务
                tx.commit();
            }catch(Exception e){
                //事务回滚
                tx.rollback();
            }finally{
                //关闭资源
                session.close();
                sessionFactory.close();
            }
        }

    Hibernate的批量抓取(会用)
    比如使用场景,需要查询所有客户(返回list)的联系人
    可以先查出list,再逐个遍历(性能低)
    这种对象导航仅仅实现了功能,却使得性能低下(发送了很多次的语句)

    完成批量抓取的优化是通过映射文件的配置完成的
    在set标签上配置属性 batch-size=""
    这里面配置一个整形,没有固定值,值越大发的语句越少,性能越高(当然应当根据数据库记录数调优)
    (可以查看底层SQL,使用的是in(?,?...)的形式,减少了语句的发送)

  • 相关阅读:
    flash动态加载多张图片
    使用ASPJPEG添加水印的方法
    利用数据库复制技术 实现数据同步更新
    ASP.NET 2.0中发送电子邮件
    .net2.0 自定义CheckBoxList验证控件
    c#动态创建存储过程中,提示'go' 附近有语法错误解决方案
    MSDB数据库置疑状态的解决方法
    ASP.NET发送邮件_相关参数
    SQL数据库msdb置疑(急)
    SQL2000数据库脱机/只读/紧急模式 修复
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6736383.html
Copyright © 2011-2022 走看看