zoukankan      html  css  js  c++  java
  • Hibernate.Criteria查询

    1.序言

    Hibernate框架是目前JavaEE软件开发的企业主流框架,学习Hibernate必然要掌握ORM(对象关系映射Object/Relation Mapping)的概念思想, Hibernate拥有完全的ORM理念,我们在操作数据库时,可以通过面向对象的方式就可以完成数据库的CRUD(创建(Create)、更新(Update)、读取(Read)和删除(Delete))操作。
    企业在使用Hibernate进行软件开发进行数据查询时,主要基于HQL(Hibernate 面向对象的查询语言,语法类似SQL)、 Criteria(面向对象的条件查询对象)、SQL(原生态SQL语句)几种方式,本文重点讲解Criteria 这种完全面向对象编程查询方式,详细分析Crieria各种使用与SQL生成关系。

    2.Criteria
    Criteria 是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现、SQL语句如何编写,是Hibernate框架的核心查询对象。
    Hibernate 定义了CriteriaSpecification接口规范用来完成面向对象的条件查询,Criteria 就是CriteriaSpecification的子接口。

     2.1数据库环境
    开发条件:
    数据库 oracleXE 10g
    用户名 jsd1606
    密码 jsd1606
     
    我们以部门(Department)和员工(Employee) 案例,来讲解Criteria的详细使用。
    (1).建表:
    (a).部门表 department 

    create table department (
    id number(10,0) not null,
    name varchar2(255 char),
    primary key (id)
    )

    (b).员工表 employee 

    create table employee (
    id number(10,0) not null,
    age number(10,0),
    birthday date,
    name varchar2(255 char),
    department_id number(10,0),
    primary key (id)
    )

    (2).插入数据
    (a).部门表 department 

    insert into department values(1,'人力资源部');
    insert into department values(2,'财务部');
    insert into department values(3,'行政部');
    insert into department values(4,'市场部');
    SQL>select * from department;
    id name
    1 人力资源部
    2 财务部
    3 行政部
    4 市场部
     

    (b).员工表 employee 
    insert into employee values(1,21,TO_DATE('1995-06-06', 'yyyy-MM-dd'),'张三',1);
    insert into employee values(2,22,TO_DATE('1994-09-26', 'yyyy-MM-dd'),'李四',1);
    insert into employee values(3,21,TO_DATE('1995-03-06', 'yyyy-MM-dd'),'王五',2);
    insert into employee values(4,22,TO_DATE('1994-08-21', 'yyyy-MM-dd'),'赵六',3);
    mysql>select * from employee;
    id name age birthday department_id
    1 张三 21 1995-06-06 1
    2 李四 22 1994-09-26 1
    3 王五 21 1995-03-06 2
    4 赵六 22 1994-08-21 3
     

    2.2.使用JPA注解配置实体类

    部门类:
    package com.axhu.entity;
    import java.util.Set;
    import javax.persistence.*;
     
    @Entity
    @Table(name="department")
    public class Department {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
     
    @Column
    private String name;
     
    @OneToMany
    @JoinColumn(name="department_id")
    private Set<Employee> employees;
    }

    员工类:
    package com.axhu.entity;
    import javax.persistence.*;
    import java.util.Date;
     
    @Entity
    @Table(name="employee ")
    public class Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
     
    @Column
    private String name;
     
    @Column
    private int age;
     
    @Temporal(TemporalType.DATE)
    private Date birthday;
     
    @ManyToOne(fetch=FetchType.LAZY)
    private Department department;
    }

    2.3使用Crteria查询所有部门和所有员工

    查询所有部门
    java代码:
    Criteria criteria = ses.createCriteria(Department.class);
    List<Department> lists= criteria.list();
    产生的SQL:
    select id,name from department
    查询结果:
    人力资源部,财务部,行政部,市场部(以toString方法打印对象,此处简写)

    查询所有员工
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    List<Employee> lists= criteria.list();
    产生的SQL:
    select id,age,birthday,department_id,name from employee
    查询结果:
    张三,李四,王五,赵六(以toString方法打印对象,此处简写)

    总结:
    当session.createCriteria(实体类.class) 就会产生一条select所有列from 表;
    SQL语句,查询实体类对应数据表的所有记录,然后我们就可以在这个Criteria对象上进行条件查询、分页查询、多表关联查询、投影查询、子查询等一系列操作……

    3.Criteria SQL定制详解

    3.1对查询添加条件对象Criterion
    org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口,一个单独的查询就是Criterion接口的一个实例,用于限制Criteria对象的查询,在Hibernate中Criterion对象的创建通常是通过Restrictions 工厂类完成的。
    Restrictions 提供条件查询方法.

    查询姓“张”的所有员工信息
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    criteria.add(Restrictions.like("name", "张%"));
    List<Employee> lists= criteria.list();
    产生的SQL:
    (1).select id,age,birthday,department_id,name
    from employee where name like ?
    (2).select id,name from department where id=?
    查询结果:
    [Employee [id=1, name=张三, age=21, birthday=1995-06-06,
    department=Department [id=1, name=人力资源部]]]

    查询年龄大于21的所有员工
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    criteria.add(Restrictions.gt("age", 21));
    List<Employee> lists= criteria.list();
    产生的主要SQL:
    select id.age,birthday,department_id,name
    from employee where age>?
    查询结果:
    李四,赵六(以toString方法打印对象,此处简写)

    查询年龄小于28的姓“王”的员工
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    criteria.add(Restrictions.lt("age", 28));
    criteria.add(Restrictions.like("name", "王%"));
    List<Employee> lists= criteria.list();
    产生的主要SQL:
    select id,age,birthday,department_id,name
    from employee where age<? and name like ?
    查询结果:
    王五(以toString方法打印对象,此处简写)

    总结:
    对于多个查询条件,Restrictions提供了逻辑组合查询方法。
    and(Criterion lhs, Criterion rhs) 用于生成多个条件and关系SQL语句; 
    or(Criterion lhs, Criterion rhs) 用于生成多个条件or关系SQL语句;
    not(Criterion expression) 用于查询与条件相反的数据,生成not取反查询语句。

    3.2分页操作 firstResult和maxResults 
    Criteria接口提供用于分页查询的方法,实现数据库SQL物理级别的分页操作。
    setFirstResult(int firstResult)设置记录的起始位置0代表第一条记录。
    setMaxResults(int maxResults)设置查询记录的长度。

    查询第1-3条员工记录(共4条记录)
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria.setFirstResult(0);
    criteria.setMaxResults(3);
    List<Employee> lists= criteria.list();
    产生的主要SQL:
    select * from
    ( select id,age,birthday,department_id,name
    from employee)
    where rownum <= ?
    查询结果:
    张三,李四,王五(以toString方法打印对象,此处简写)

    查询第2-4条员工记录(共3条记录)
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    criteria.setFirstResult(1);
    criteria.setMaxResults(3);
    List<Employee> lists = criteria.list();
    产生的主要SQL:
    select * from
    ( select e.*,rownum rum
    from (
    select id,age,birthday,department_id,name
    from employee
    ) e
    where rownum <= ?
    ) where rum > ?
    查询结果:
    李四,王五,赵六(以toString方法打印对象,此处简写)

    3.3排序操作 Order
    Hibernate提供org.hibernate.criterion.Order用于排序操作,Criteria接口提供addOrder(Order order)用于生成排序SQL.

    查询所有员工信息,按照年龄升序(asc)/降序(desc)排列。
    java代码:
    Criteria criteria= ses.createCriteria(Employee.class);
    criteria.addOrder(Order.asc("age"));//Order.desc("age")
    List<Employee> lists = criteria.list();
    产生的主要SQL:
    select id,age,birthday,department_id,name
    from employee order by age asc/desc
    查询结果:(以toString方法打印对象,此处简写)
    asc:王五(21),张三(21),赵六(22),李四(22)
    desc:李四(22),赵六(22),王五(21),张三(21)

    3.4多表关联操作createAlias和createCriteria
    Criteria接口提供createAlias和createCriteria两组方法用于完成多表关联查询.
    createAlias(String associationPath, String alias) 采用内连接关联.
    createAlias(String associationPath, String alias, int joinType)
    可以通过joinType指定连接类型.
    createCriteria(String associationPath) 采用内连接关联(返回新的Criteria对象)。
    createCriteria(String associationPath, int joinType)
    可以通过joinType指定关联类型(返回新的Criteria对象).

    查询部门为“人力资源部”的所有员工(使用createCriteria方法)
    java代码:
    Criteria criteria1 = ses.createCriteria(Employee.class);
    Criteria criteria2 = criteria1.createCriteria("department");
    criteria2.add(Restrictions.eq("name", "人力资源部"));
    List<Employee> lists= criteria.list();
    产生的主要SQL:
    select e.id,e.age,e.birthday,e.department_id,e.name,d.id,d.name
    from employee e
    inner join department d on e.department_id=d.id
    where d.name=?
    查询结果:
    张三,李四(以toString方法打印对象,此处简写)
    注意事项:
    Criteria criteria1和Criteria criteria2一定要是两个对象,不能在一个对象中直接获取.

    总结:
    代码中的criteria对象,是针对employee表,criteria.createCriteria(”department”) 就是建立employee表和department表的内连接.返回的是针对department表新的criteria2对象,这时再对criteria2 添加条件,就是查询department部门表的属性,而不是employee的属性了.

    查询部门为“人力资源部”的所有员工(使用createAlias方法)
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria .createAlias("department","d");
    criteria .add(Restrictions.eq("d.name", "人力资源部"));
    List<Employee> lists = criteria .list();
    产生的主要SQL:
    select e.id,e.age,e.birthday,e.department_id,e.name,d.id,d.name
    from employee e
    inner join department d
    on e.department_id=d.id
    where d.name=?
    查询结果:
    张三,李四(以toString方法打印对象,此处简写)

    3.5.投影、分组查询 Projection
    在实际开发中,进行查询是:可能只需要返回表中的指定列信息(投影)或者进行统计查询(count,avg,sum,min,max).
    Criteria接口提供setProjection(Projection projection)方法用于实现投影查询操作.
    org.hibernate.criterion.Projections工厂类用于返回Projection投影查询对象.

    查询员工表的name和age属性
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria .setProjection(
    Projections.projectionList()
    .add(Projections.property("name"))
    .add(Projections.property("age")));
    List<Object> objs= criteria .list();
    或:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria .setProjection(
    Projections.projectionList()
    .add(Property.forName("name"))
    .add(Property.forName("age")));
    List<Object> objs= criteria .list();
    产生的主要SQL:
    select name,age from employee
    查询结果:
    Object,Object,Object,Object

    查询员工的总数量
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria.setProjection(Projections.rowCount());
    Long row = (Long) criteria.uniqueResult();
    产生的主要SQL:
    select count(*) from employee
    查询结果:
    4

    总结:
    rowCount() 查询记录总数量;
    count(String propertyName) 统计某列数量;
    countDistinct(String propertyName) 统计某列数(排除重复);
    avg(String propertyName) 统计某列平均值;
    sum(String propertyName) 对某列值求和;
    max(String propertyName) 求某列最大值;
    min(String propertyName) 求某列最小值;

    查询每个部门的员工数量(输出部门的编号和数量)
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria.setProjection(
    Projections.projectionList()
    .add(Projections.groupProperty("department"))
    .add(Projections.count("id")));
    List<Object> lists = criteria.list();
    产生的主要SQL:
    select e.department_id,count(e.id)
    from employee e group by e.department_id
    查询结果:
    Object,Object,Object

    3.6. 设置结果集封装策略 ResultTransformer
    刚刚说了投影操作的使用,其实在Hibernate内部投影查询是会影响到结果集的封装策略的.先用HQL举例说明:
    session.createQuery(”from Employee”).list();//返回 List
    session.createQuery(”select count(e) from Employee e”).list();//返回List
    session.createQuery(”select name,age from Employee”).list();//返回List
    从这几个例子我们不难发现,如果没有指定select语句(没有投影),那么将返回表中的所有字段,返回结果会被封装到Entity实体对象Employee中,一但提供select语句(投影)后,返回的结果类型,将不再封装到Employee对象,而是根据投影的实际类型返回,这就是投影对结果封装策略的影响.
    我们再来看之前写过的Criteria 查询案例:
    session.createCriteria(Employee.class).list();//返回 List
    session.createCriteria(Employee.class).setProjection(
    Projections.projectionList()
    .add(Property.forName(”name”))
    .add(Property.forName(”age”)));//返回 List
    投影之后,返回的结果将不再被封装到Employee对象中,这是为什么呢?
    我们一起来看看 Criteria的接口定义,不难发现在Criteria接口中提供了一个setResultTransformer(ResultTransformer resultTransformer),这个ResultTransformer就是结果集转换策略接口,在Criteria的父接口中CriteriaSpecification定义了几个ResultTransformer的常用实现.
    ALIAS_TO_ENTITY_MAP 将结果集封装到Map对象;
    ROOT_ENTITY 将结果集封装到根实体对象;
    DISTINCT_ROOT_ENTITY 将结果集封装到不重复的根实体对象;
    PROJECTION 根据投影的结果类型自动封装;
    当进行投影查询时,结果的封装策略由ROOT_ENTITY 变为了PROJECTION,所以是根据查询数据进行封装,而不是封装到根对象.
    了解上面原理后,即使只查询name和age属性,也可以封装成List集合.

    使用AliasToBeanResultTransformer 修改结果封装策略,AliasToBeanResultTransformer 会根据返回列自动匹配类中属性名,完成封装
    java代码:
    Criteria criteria = ses.createCriteria(Employee.class);
    criteria.setProjection(
    Projections.projectionList()
    .add(Projections.property("name").as("name"))
    .add(Projections.property("age").as("age")));
    criteria.setResultTransformer(
    new AliasToBeanResultTransformer(Employee.class));
    List<Employee[]> lists = criteria.list();
    产生的主要SQL:
    select e.name,e.age from employee
    查询结果:
    [Employee [id=null, name=张三, age=21, birthday=null, department=null],
    Employee [id=null, name=李四, age=22, birthday=null, department=null],
    Employee [id=null, name=王五, age=21, birthday=null, department=null],
    Employee [id=null, name=赵六, age=22, birthday=null, department=null]]

    4.附录

    测试代码:
    @Test
    public void test() throws HibernateException{
    Session ses = null;
    Transaction tx = null;
    try {
    ses = SessionUtil.getSession();
    tx = ses.beginTransaction();
    Criteria criteria = ses.createCriteria(Department.class);
    List<Department> lists= criteria.list();
    System.out.println(lists);
    tx.commit();
    } catch (HibernateException e) {
    // TODO Auto-generated catch block
    if(null!=tx){
    tx.rollback();
    }
    e.printStackTrace();
    }finally{
    SessionUtil.closeSession(ses);
    }
    }

    工具类:
    public class SessionUtil {
    private static SessionFactory sf = null;
    /**
    * 通过静态代码块来创建SessionFactory
    */
    static{
    try {
    //1.启动hibernate.cfg.xml配置文件,通过Configuration类
    Configuration cfg = new Configuration();
    //2.调用configure()方法来去加载src根目录下面的hibernate.cfg.xml文件
    //注意:configure(String path);//重载方法,用来加载指定目录下的配置文件.
    cfg.configure();
    //3.创建SessionFactory(充当数据源的一个代理,重量级的对象)
    //通常一个数据库只需要配置一个SesisonFactory对象.通过这个
    //对象,可以获取Session(Connection+Cache)
    //3-1.hibernate3.x创建方式(已经过时了)
    //SessionFactory sf = cfg.buildSessionFactory();
    //3-2.hibernate4.x创建方式
    ServiceRegistry sr = new StandardServiceRegistryBuilder()
    .applySettings(cfg.getProperties()).build();
    sf = cfg.buildSessionFactory(sr);
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    throw new RuntimeException(e);
    }
    }
     
    /**
    * 获取Session
    */
    public static Session getSession() throws HibernateException{
    return sf==null?null:sf.openSession();
    }
    /**
    * 关闭session
    */
    public static void closeSession(Session ses){
    if(null!=ses){
    ses.close();
    }
    }
    }

     说明:该文系参考网上,现找不到该原文(我没找到).特此说明,向原博主致敬

    author : ily
    address : anhui hefei
     
     




    出自博客 http://www.cnblogs.com/yunlei0821/,欢迎留言补充指正,仅供互相交流学习.转载请务必保留此出处..

    本文为作者原创 ,欢迎转载和收藏,转载请保留作者及出处,谢谢您的配合,如有侵权,请第一时间联系 yunlei0821@vip.qq.com,以便及时删除...

    晨露&无尘
  • 相关阅读:
    【leetcode】416. Partition Equal Subset Sum
    【leetcode】893. Groups of Special-Equivalent Strings
    【leetcode】892. Surface Area of 3D Shapes
    【leetcode】883. Projection Area of 3D Shapes
    【leetcode】140. Word Break II
    【leetcode】126. Word Ladder II
    【leetcode】44. Wildcard Matching
    【leetcode】336. Palindrome Pairs
    【leetcode】354. Russian Doll Envelopes
    2017.12.22 英语面试手记
  • 原文地址:https://www.cnblogs.com/yunlei0821/p/6601776.html
Copyright © 2011-2022 走看看