Hibernate各种查询(下)

分页查询

MySQL实现分页

  • 使用关键字 limit 实现
select * from user limit 0,3

在hql中实现分页

  • 在hql操作中,在语句里面不能写limit。
    @Test
    public void showSelectPage(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();

        //查询要分页的数据
        Query query=session.createQuery("from Role");
        //设置开始位置
        query.setFirstResult(2);
        //设置每页的数据量
        query.setMaxResults(3);
        List<Role> roles=query.list();

        for(Role i:roles){
            System.out.println(i);
        }
        transaction.commit();
    }

查询通过分页查询,查询两个字段:

    @Test
    public void showSelectPage(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();

        //查询要分页的数据
        Query query=session.createQuery("select rname,rmemo from Role");
        //设置开始位置
        query.setFirstResult(2);
        //设置每页的数据量
        query.setMaxResults(3);
        List<Object[]> roles=query.list();

        for(Object i[]:roles){
            System.out.println((String)i[0]+"----"+(String)i[1]);
        }
        transaction.commit();
    }

//在里面查询单个值的时候可以用String,Integer等,查询多个值的时候要用Object。

投影查询

投影查询:查询不是所有字段值,而是部分字段的值。

投影查询hql语法:

  • select 实体类属性名称1,实体类属性名称2 from 实体类名称
  • select 后面不能写 “*” 号,Hibernate是不支持的。

其实在上面我们已经用到了投影查询。

面再作演示:

    @Test
    public void showTouYingAgain(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Query<String> query=session.createQuery("select rname from Role");//Query加泛型的原因是笔者用的版本从5.1更新到5.2.8后,Hibernate对Query加了泛型。
        for(String i:query.list()){
            System.out.println(i);
        }

        transaction.commit();
    }

HQL多表查询

HQL多表查询:

  • 内连接
  • 左外连接
  • 右外连接
  • 迫切内连接
  • 迫切左外连接
//MySQL语句写法
//内连接查询,查询左右表同时满足的数据
//内连接不作条件处理,相当于对两个表做了排列组合。
select * from customer c,linkman l where c.cid=l.clid
select * from customer c inner join linkman l on c.cid=l.clid

//左外连接
//把左表的数据全部输出来,右表只做关联显示,不管是否满足都会显示。
select * from customer c left outer join linkman l on c.cid=l.clid

//右外连接
//同样,右边显示全部,左边显示关联数据
select * from customer c right outer join linkman l on c.cid=l.clid

什么是左外连接和右外连接:

两个表:
A(id,name)
数据:(1,张三)(2,李四)(3,王五)
B(id,name)
数据:(1,学生)(2,老师)(4,校长)
左连接结果:
select A.*,B.* from A left join B on A.id=B.id;
1 张三 1 学生
2 李四 2 老师
3 王五 NULL NULL
右链接结果:
select A.*,B.* from A right join B on A.id=B.id;
1 张三 1 学生
2 李四 2 老师
NULL NULL 4 校长
****************
补充:下面这种情况就会用到外连接
比如有两个表一个是用户表,一个是交易记录表,如果我要查询每个用户的交易记录就要用到左外外连接,因为不是每个用户都有交易记录。
用到左外连接后,有交易记录的信息就会显示,没有的就显示NULL,就像上面我举得例子一样。
如果不用外连接的话,比如【王五】没有交易记录的话,那么用户表里的【王五】的信息就不会显示,就失去了查询所有用户交易记录的意义了。
****************
看一下结果就能明白左右连接的区别了。

HQL内连接:

  • 这里是用的多对多表关系。
//通过where限制
    @Test
    public void showAgain(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Query<Object> query=session.createQuery("select r.rname from Role r inner join r.userSet c where r.rname!=c.uname");
        for(Object i:query.list()){
            System.out.println(i);
        }
        transaction.commit();
    }
//输出结果:

Hibernate: 
    select
        role0_.rname as col_0_0_ 
    from
        role role0_ 
    inner join
        user_role userset1_ 
            on role0_.rid=userset1_.frid 
    inner join
        user user2_ 
            on userset1_.fuid=user2_.uid 
    where
        role0_.rname<>user2_.uname
开发工程师
架构师
狼神总部副总裁
图像算法师
骇客
    @Test
    public void showNormal(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Query<Object> query=session.createQuery("select r.rname from Role r inner join r.userSet");
        for(Object i:query.list()){
            System.out.println(i);
        }
        transaction.commit();
    }
    //注意这个查询并没有写条件。所以这个hql语句只是把,三张表连接起来了而已。
//输出结果:

Hibernate: 
    select
        role0_.rname as col_0_0_ 
    from
        role role0_ 
    inner join
        user_role userset1_ 
            on role0_.rid=userset1_.frid 
    inner join
        user user2_ 
            on userset1_.fuid=user2_.uid
开发工程师
架构师
狼神总部副总裁
图像算法师
骇客
//通过 on 来进行限制
    @Test
    public void showAgain(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Query<Object> query=session.createQuery("select r.rname from Role r inner join r.userSet c on r.rname!=c.uname");
        for(Object i:query.list()){
            System.out.println(i);
        }
        transaction.commit();
    }
//输出结果:
Hibernate: 
    select
        role0_.rname as col_0_0_ 
    from
        role role0_ 
    inner join
        (
            user_role userset1_ 
        inner join
            user user2_ 
                on userset1_.fuid=user2_.uid
            ) 
                on role0_.rid=userset1_.frid 
                and (
                    role0_.rname<>user2_.uname
                )
开发工程师
架构师
狼神总部副总裁
图像算法师
骇客

迫切内连接

  • 迫切内连接和内连接底层实现都一样
  • 区别:使用内连接返回list中每部分是数组,迫切内连接返回list每部分是对象。

hql的语法写法:

from Role c inner join fetch c.userSet
    @Test
    public void shoFetchLink(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Query<Role> query=session.createQuery("from Role r inner join fetch r.userSet");//注意:用迫切内连接是不能够只查表中的一部分数据。否则返回的是一个数组。
        List<Role> result=query.list();
        for(Role i:result){
            System.out.println(i);
        }
        transaction.commit();
    }
//输出结果:

Hibernate: 
    select
        role0_.rid as rid1_0_0_,
        user2_.uid as uid1_1_1_,
        role0_.rname as rname2_0_0_,
        role0_.rmemo as rmemo3_0_0_,
        user2_.uname as uname2_1_1_,
        user2_.pword as pword3_1_1_,
        userset1_.frid as frid1_2_0__,
        userset1_.fuid as fuid2_2_0__ 
    from
        role role0_ 
    inner join
        user_role userset1_ 
            on role0_.rid=userset1_.frid 
    inner join
        user user2_ 
            on userset1_.fuid=user2_.uid
Role [rid=1, rname=开发工程师, rmemo=专注于网页前后台开发,和图像算法!!]
Role [rid=2, rname=架构师, rmemo=进行程序开发架构!]
Role [rid=3, rname=狼神总部副总裁, rmemo=国际知名企业!!]
Role [rid=4, rname=图像算法师, rmemo=通过代码对程序的算法处理!以及识别!!]
Role [rid=6, rname=骇客, rmemo=网络安全工程师]

HQL左外连接

左外连接HQL语句

  • from Customer c left outer join c.setLinkMan
  • 迫切左外连接:from Customer c left outer join fetch c.setLinkMan
//左外连接

    @Test
    public void shoFetchLink(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Query<Role> query=session.createQuery("from Role r inner join fetch r.userSet");
        List<Role> result=query.list();
        for(Role i:result){
            System.out.println(i);
        }
        transaction.commit();
    }
//因为我们这里的主表是Role所以我们会查出四个结果,同时也会输出两个表的信息。
//输出结果:
Hibernate: 
    select
        role0_.rid as rid1_0_0_,
        user2_.uid as uid1_1_1_,
        role0_.rname as rname2_0_0_,
        role0_.rmemo as rmemo3_0_0_,
        user2_.uname as uname2_1_1_,
        user2_.pword as pword3_1_1_ 
    from
        role role0_ 
    left outer join
        user_role userset1_ 
            on role0_.rid=userset1_.frid 
    left outer join
        user user2_ 
            on userset1_.fuid=user2_.uid
Role [rid=1, rname=架构师, rmemo=进行程序开发架构!]
Hibernate: 
    select
        roleset0_.fuid as fuid2_2_0_,
        roleset0_.frid as frid1_2_0_,
        role1_.rid as rid1_0_1_,
        role1_.rname as rname2_0_1_,
        role1_.rmemo as rmemo3_0_1_ 
    from
        user_role roleset0_ 
    inner join
        role role1_ 
            on roleset0_.frid=role1_.rid 
    where
        roleset0_.fuid=?
User [uid=1, uname=LangSheng, pword=123456, roleSet=[Role [rid=1, rname=架构师, rmemo=进行程序开发架构!], Role [rid=2, rname=开发工程师, rmemo=专注于网页前后台开发,和图像算法!!]]]
Role [rid=2, rname=开发工程师, rmemo=专注于网页前后台开发,和图像算法!!]
User [uid=1, uname=LangSheng, pword=123456, roleSet=[Role [rid=1, rname=架构师, rmemo=进行程序开发架构!], Role [rid=2, rname=开发工程师, rmemo=专注于网页前后台开发,和图像算法!!]]]
Role [rid=3, rname=图像算法师, rmemo=通过代码对程序的算法处理!以及识别!!]
Hibernate: 
    select
        roleset0_.fuid as fuid2_2_0_,
        roleset0_.frid as frid1_2_0_,
        role1_.rid as rid1_0_1_,
        role1_.rname as rname2_0_1_,
        role1_.rmemo as rmemo3_0_1_ 
    from
        user_role roleset0_ 
    inner join
        role role1_ 
            on roleset0_.frid=role1_.rid 
    where
        roleset0_.fuid=?
User [uid=2, uname=FireLang, pword=456123, roleSet=[Role [rid=4, rname=狼神总部副总裁, rmemo=国际知名企业!!], Role [rid=3, rname=图像算法师, rmemo=通过代码对程序的算法处理!以及识别!!]]]
Role [rid=4, rname=狼神总部副总裁, rmemo=国际知名企业!!]
User [uid=2, uname=FireLang, pword=456123, roleSet=[Role [rid=4, rname=狼神总部副总裁, rmemo=国际知名企业!!], Role [rid=3, rname=图像算法师, rmemo=通过代码对程序的算法处理!以及识别!!]]]
//在第二个for循环里面,有两个对象,一个是Role,另外一个是User

迫切左外连接:

    @Test
    public void showLeftOuterJoinfetch(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();

        Query<Role> query=session.createQuery("from Role r left outer join fetch r.userSet");
        List<Role> users=query.list();
        for(Role i:users){
                System.out.println(i);
        }
        transaction.commit();
    }
Hibernate: 
    select
        role0_.rid as rid1_0_0_,
        user2_.uid as uid1_1_1_,
        role0_.rname as rname2_0_0_,
        role0_.rmemo as rmemo3_0_0_,
        user2_.uname as uname2_1_1_,
        user2_.pword as pword3_1_1_,
        userset1_.frid as frid1_2_0__,
        userset1_.fuid as fuid2_2_0__ 
    from
        role role0_ 
    left outer join
        user_role userset1_ 
            on role0_.rid=userset1_.frid 
    left outer join
        user user2_ 
            on userset1_.fuid=user2_.uid
Role [rid=1, rname=架构师, rmemo=进行程序开发架构!]
Role [rid=2, rname=开发工程师, rmemo=专注于网页前后台开发,和图像算法!!]
Role [rid=3, rname=图像算法师, rmemo=通过代码对程序的算法处理!以及识别!!]
Role [rid=4, rname=狼神总部副总裁, rmemo=国际知名企业!!]

右外连接:

  • from Customer c right outer join c.setLinkMan

QBC查询

查询所有

  • 创建Criteria对象
  • 调用方法就可以得到

Java代码:

    @Test
    public void showCriteria(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Criteria criteria=session.createCriteria(Customer.class);
        List<Customer> customers=criteria.list();
        for(Customer i:customers){
            System.out.println(i);
        }
        transaction.commit();
    }

条件查询:

这里写图片描述

    @Test
    public void showCriteriaTiaoJian(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Criteria criteria=session.createCriteria(Customer.class);
        //使用add方法,表示设置条件值。
        criteria.add(Restrictions.like("custName", "%科技%"));
        //这里可以写多个add来进行添加条件。
        List<Customer> customers=criteria.list();
        for(Customer i:customers){
            System.out.println(i);
        }

        transaction.commit();
    }

排序查询:

    @Test
    public void orderX(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Criteria criteria=session.createCriteria(Customer.class);
        criteria.addOrder(Order.desc("cid"));//这里Order有两个静态方法,一个是desc(),一个是asc();
        List<Customer> customers=criteria.list();
        for(Customer i:customers){
            System.out.println(i);
        }

        transaction.commit();
    }

分页查询:

    @Test
    public void showLimit(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Criteria criteria=session.createCriteria(Customer.class);
        //设置开始的位置
        criteria.setFirstResult(0);
        //设置每页显示的个数
        criteria.setMaxResults(3);
        List<Customer> customers=criteria.list();
        for(Customer i:customers){
            System.out.println(i);
        }

        transaction.commit();
    }
    //开始位置计算公式:(当前页-1)*每页记录数

统计查询:

    @Test
    public void showCount(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Criteria criteria=session.createCriteria(Customer.class);

        //设置要使用的聚集函数
        criteria.setProjection(Projections.rowCount());

        Object count=criteria.uniqueResult();
        int countnum=((Long)count).intValue();
        System.out.println(countnum);
        transaction.commit();
    }

离线查询:

  • 跟session没有关联的操作就是离线查询。
  • 离线查询能够和Criteria一样,能够查询很多东西,比如统计查询、条件查询等。
  • 但是最终我们要进行获取数据库中的数据时,还是会通过session来查询数据库。
//这是一个离线查询的简单演示。到了后面我们还会详细介绍。
    @Test
    public void showDatched(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();

        DetachedCriteria detachedCriteria=DetachedCriteria.forClass(Customer.class);

        Criteria criteria = detachedCriteria.getExecutableCriteria(session);
        List<Customer> customers=criteria.list();
        for(Customer i:customers){
            System.out.println(i);
        }
        transaction.commit();
    }

为什么要用离线查询??大家可以看到一个特点,那就是离线查询能够延迟查询的时间或者说是能够让查询的逻辑代码在未执行前与session无关,也就是说我们能够在Servlet层或者其它层把查询的逻辑代码写出来,再传到Dao层进行查询。

session.createCriteria(Role.class);//这个方法以及过时了,官方说要用Jpa Criteria。其中有很多Jpa概念笔者还不懂,在后续我会更新的。

SQLQuery查询

基本使用请看博客

SQLQuery在Hibernate5.2.8里面已经过时了。取而代之的是NativeQuery,但是这个NativeQuery是个接口,而且这个接口里面的方法不能够作基本用途,所以我们要用它的实现类来做载体,NativeQueryImpl。下面是个简单例子:

我这里用的是Hibernate5.2.8的jar包

Hibernate5.2.8提取jar包下载

    @Test
    public void showSigleQuery(){
        Session session=HibernateUtils.getSessionFactory().openSession();
        Transaction transaction=session.beginTransaction();
        NativeQueryImpl<User> nativeQuery=(NativeQueryImpl<User>)session.createNativeQuery("select * from user");

        List<User> list=nativeQuery.addEntity(User.class).list();

        for(User i:list){
            System.out.println(i);
        }

        transaction.commit();
    }

几种查询后我想说个东西:对于查询的方法我们已经学了三个了QBC查询、HQL查询、SQLQuery查询。这三个里面有很多都能够互相替代。所以在这两个里面不管我们用什么,只要我们熟悉那个就用哪个。公司要求用哪个就用哪个。没有绝对的限制。

Hibernate检索策略

Hibernate检索策略分为两类:

  1. 立即查询:根据id查询,调用get方法,一调用get方法马上发送语句查询数据库。
Customer customer=session.get(Customer.class,1);
System.out.println(customer.getCid());
  1. 延迟查询:根据id查询,调用load方法,调用load方法并不会马上发送语句查询数据库,只有要得到对象里面的值的时候才会发送语句查询数据库。其中调用load方法会返回一个对象
    该对象里面只有一个值,那就是id。当我们要得到id的时候并不会发送语句查询数据库,只有要得到除了id以外的数据时才会查询数据库。
Customer customer=session.load(Customer.class,1);
System.out.println(customer.getCid());
System.out.println(customer.getCustName());

延迟查询分成两类:

  1. 类级别延迟:根据id查询返回实体类对象,调用load方法不会马上发送语句。上面调用load方法就是类级别延迟。

  2. 关联级别延迟:查询某个客户,在查询这个客户的所有联系人,查询客户的所有联系人的过程是否需要延迟,这个过程称为关联级别延迟。

默认延迟效果:

//这个时候会查询id为1的客户
Customer customer = session.get(Customer.class,1);

//这个步骤在Hibernate中作了优化的。不会发送语句查询数据库。
Set<LinkMan> linkman=customer.getSetLinkMan();

//发送语句
System.out.println(linkman.size());

关联级别延迟操作设置

在映射文件中进行配置实现

这里写图片描述

  1. 这里是一对多操作,客户一,联系人多。所以在客户里面进行配置。

  2. 在set标签上使用属性

    • fetch:值select(默认)
    • lazy:值

true:延迟(默认)
false:不延迟
extra:极其延迟

fetch="select" lazy="true"
//效果和上面的关联延迟效果一样。
fetch="select" lazy="false"
//不延迟,查询值的时候直接把值给查询出来,比如查询上面Set<LinkMan> linkman=customer.getSetLinkMan();的时候就会发送语句查询数据库。并不会发生延迟
fetch="select" lazy="extra"
//极其延迟,要什么给什么值,比如上面我们Set<LinkMan> linkman=customer.getSetLinkMan();这个步骤不会发送语句查询数据库。在linkman.size()的时候才会发送语句查询数据库
//但是查询数量的时候并不是查询出所有的联系人再数数量,而是通过sql函数count查询出值。明显效率比较高。

批量抓取

现在我们有个需求:查询所有客户,返回list集合,遍历list集合,得到每个客户,得到每个客户的所有联系人。

演示问题:

这里使用的是一对多的关系。

配置文件:

        <set name="linkMans" cascade="save-update" inverse="true" >
            <key column="clid"></key>
            <one-to-many class="cn.domarvel.entity.LinkMan"/>
        </set>
//一般我们写的代码:
    @Test
    public void showAll(){
        Session session=HibernateUtils.getCurrentSession();
        Transaction transaction=session.beginTransaction();
        Query query=session.createQuery("from Customer");
        List<Customer> customers=query.list();
        for(Customer i:customers){
            System.out.println(i.getCustName());
            for(LinkMan j:i.getLinkMans()){
                System.out.println(j);
            }
            System.out.println("##############################");
        }
        transaction.commit();
    }
    //据说这样效率不行。查询数据库次数太多。

为了改善查询数据库次数太多:

我们这里引入一个配置属性:batch-size,属性值为>=1,指的是一次查询数据的多少。1为一条,2为2条,默认为1条。值的设置和你本身的需求有关。

示例配置:

        <set name="linkMans" cascade="save-update" inverse="true" batch-size="10">
            <key column="clid"></key>
            <one-to-many class="cn.domarvel.entity.LinkMan"/>
        </set>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值