Hibernate之检索方式(HQL/QBC/本地SQL)

一、概述

  • Hibernate提供了以下几种检索对象的方式

    • 导航对象图:根据已经加载的对象导航到其它对象

    • OID:按照对象的OID来检索对象

    • HQL:使用面向对象的HQL查询语句

    • QBC:使用QBC(Query By Criteria)API来检索对象

    • 本地SQL:使用本地数据库的SQL查询语句

二、HQL

  • HQL是面向对象的查询语句,它有如下功能:

    • 在查询语句中设定各种查询条件

    • 支持投影查询,即仅检索出对象的部分属性

    • 支持分页查询

    • 支持连接查询

    • 支持分组查询

    • 提供内置聚集函数

    • 支持子查询

    • 支持动态绑定参数

    • 能够调用用户定义的SQL函数或标准的SQL函数

  • 步骤:

1.通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句。HQL查询语句中可以包含命名参数

2.动态绑定参数

3.调用Query相关方法执行查询语句

  • Query接口支持方法链编程风格,它的setXxx()方法返回自身实例

  • 绑定参数

    • Hibernate的参数绑定机制依赖于JDBC API中的PreparedStatement的预定义SQL语句功能

    • HQL的参数绑定有两种形式:

      • 按参数名字绑定:命名参数以“:”开头

      • 按参数位置绑定:用"?"来定义参数位置

    • 相关方法:

      • setEntity():把参数与一个持久化类绑定

      • setParameter():绑定任意类型的参数,该方法的第三个参数显示指定Hibernate映射类型

  • HQL采用ORDER BY关键字对查询结果排序

实体类(对应的配置文件省略)

Department.java

public class Department {
​
    private Integer id;
    private String name;
    
    private Set<Employee> emps = new HashSet<>();
}

Employee.java

public class Employee {
​
    private Integer id;
    private String name;
    private float salary;
    private String email;
  
    
    public Employee() {}
  
    public Employee(String email, float salary, Department dept) {
        this.salary = salary;
        this.email = email;
        this.dept = dept;
    }
​
  
  ///get(),set()方法
}

测试:

    private SessionFactory sessionFactory;
    private Session session;
    private Transaction transaction;
    
    @Before
    public void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = 
                new ServiceRegistryBuilder().applySettings(configuration.getProperties())
                                            .buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }
    
    @After
    public void destroy(){
        transaction.commit();
        session.close();
        sessionFactory.close();
    }
​
    @Test
    public void testHQLNamedParameter(){
        
        //1. 创建 Query 对象
        //基于命名参数. 
        String hql = "FROM Employee e WHERE e.salary > :sal AND e.email LIKE :email";
        Query query = session.createQuery(hql);
        
        //2. 绑定参数
        query.setFloat("sal", 7000)
             .setString("email", "%A%");
        
        //3. 执行查询
        List<Employee> emps = query.list();
        System.out.println(emps.size());  
    }
    
    @Test
    public void testHQL(){
        
        //1. 创建 Query 对象
        //基于位置的参数. 
        String hql = "FROM Employee e WHERE e.salary > ? AND e.email LIKE ? AND e.dept = ? "
                + "ORDER BY e.salary";
        Query query = session.createQuery(hql);
        
        //2. 绑定参数
        //Query 对象调用 setXxx 方法支持方法链的编程风格.
        Department dept = new Department();
        dept.setId(80); 
        query.setFloat(0, 6000)
             .setString(1, "%A%")
             .setEntity(2, dept);
        
        //3. 执行查询
        List<Employee> emps = query.list();
        System.out.println(emps.size());  
    }

分页查询

  • setFirstResult(int firstResult):设定从哪一个对象开始索引(起始值为0)

  • setMaxResults(int maxResults):设定一次最多索引出的对象的数目

    @Test
    public void testPageQuery(){
        String hql = "FROM Employee";
        Query query = session.createQuery(hql);
        //当前页
        int pageNo = 22;
        //每页的记录数
        int pageSize = 5;
        
        List<Employee> emps = 
                                query.setFirstResult((pageNo - 1) * pageSize)
                                     .setMaxResults(pageSize)
                                     .list();
        System.out.println(emps);
    }

在映射文件中定义命名查询语句

  • Hibernate允许在映射文件中定义字符串形式的查询语句

  • <query>元素用于定义一个HQL查询语句,它和<class>元素并列

  • 在程序中通过Session的getNamedQuery()方法获取查询语句对应的Query对象

    <query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>
    @Test
    public void testNamedQuery(){
        Query query = session.getNamedQuery("salaryEmps");
        
        List<Employee> emps = query.setFloat("minSal", 5000)
                                   .setFloat("maxSal", 10000)
                                   .list();
        
        System.out.println(emps.size()); 
    }

投影查询

  • 查询结果仅包含实体的部分属性,通过select关键字实现

  • list()方法返回的集合中包含的是数组类型的元素,每个对象数组代表查询结果的一条记录

  • 可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录

  • 可以通过distinct关键字来保证查询结果不会返回重复元素

    @Test
    public void testFieldQuery2(){
        String hql = "SELECT new Employee(e.email, e.salary, e.dept) "
                + "FROM Employee e "
                + "WHERE e.dept = :dept";
        Query query = session.createQuery(hql);
        
        Department dept = new Department();
        dept.setId(80);
        List<Employee> result = query.setEntity("dept", dept)
                                     .list();
        
        for(Employee emp: result){
            System.out.println(emp.getId() + ", " + emp.getEmail() 
                    + ", " + emp.getSalary() + ", " + emp.getDept());
        }
    }
    
    @Test
    public void testFieldQuery(){
        String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept";
        Query query = session.createQuery(hql);
        
        Department dept = new Department();
        dept.setId(80);
        List<Object[]> result = query.setEntity("dept", dept)
                                     .list();
        
        for(Object [] objs: result){
            System.out.println(Arrays.asList(objs));
        }
    }

报表查询

  • 报表查询用于对数据分组和统计

  • 在HQL查询语句中可以调用以下聚集函数

    • count()

    • min()

    • max()

    • sum()

    • avg()

    @Test
    public void testGroupBy(){
        String hql = "SELECT min(e.salary), max(e.salary) "
                + "FROM Employee e "
                + "GROUP BY e.dept "
                + "HAVING min(salary) > :minSal";
        
        Query query = session.createQuery(hql)
                             .setFloat("minSal", 8000);
        
        List<Object []> result = query.list();
        for(Object [] objs: result){
            System.out.println(Arrays.asList(objs));
        }
    }

迫切左外连接

  • left join fetch关键字

  • list()方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee 集合都被初始化, 存放所有关联的 Employee 的实体对象

  • 查询结果中可能会包含重复元素, 可以通过一个 HashSet 来过滤重复元素

    @Test
    public void testLeftJoinFetch(){
//      String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps";
        String hql = "FROM Department d INNER JOIN FETCH d.emps";
        Query query = session.createQuery(hql);
        
        List<Department> depts = query.list();
        depts = new ArrayList<>(new LinkedHashSet(depts));
        System.out.println(depts.size()); 
        
        for(Department dept: depts){
            System.out.println(dept.getName() + "-" + dept.getEmps().size());
        }
    }

左外连接:

  • left join关键字

  • list()方法返回的集合中存放的是对象数组类型

  • 根据配置文件来决定Employee集合的检索策略

  • 如果希望list()方法返回的集合中包含Department对象,可以在HQL查询语句中使用select关键字

    @Test
    public void testLeftJoin(){
        String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN d.emps";
        Query query = session.createQuery(hql);
        
        List<Department> depts = query.list();
        System.out.println(depts.size());
        
        for(Department dept: depts){
            System.out.println(dept.getName() + ", " + dept.getEmps().size()); 
        }
        
//      String hql = "FROM Department d LEFT JOIN d.emps";
//      List<Object []> result = query.list(); 
//      result = new ArrayList<>(new LinkedHashSet<>(result));
//      System.out.println(result); 
//      
//      for(Object [] objs: result){
//          System.out.println(Arrays.asList(objs));
//      }
    }

(迫切)内连接(原理同上)

    @Test
    public void testLeftJoinFetch2(){
        String hql = "SELECT e FROM Employee e INNER JOIN e.dept";
        Query query = session.createQuery(hql);
        
        List<Employee> emps = query.list();
        System.out.println(emps.size()); 
        
        for(Employee emp: emps){
            System.out.println(emp.getName() + ", " + emp.getDept().getName());
        }
    }

三、QBC

  • QBC查询就是通过使用Hibernate提供的QBC API来查询对象

    @Test
    public void testQBC4(){
        Criteria criteria = session.createCriteria(Employee.class);
        
        //1. 添加排序
        criteria.addOrder(Order.asc("salary"));
        criteria.addOrder(Order.desc("email"));
        
        //2. 添加翻页方法
        int pageSize = 5;
        int pageNo = 3;
        criteria.setFirstResult((pageNo - 1) * pageSize)
                .setMaxResults(pageSize)
                .list();
    }
    
    @Test
    public void testQBC3(){
        Criteria criteria = session.createCriteria(Employee.class);
        
        //统计查询: 使用 Projection 来表示: 可以由 Projections 的静态方法得到
        criteria.setProjection(Projections.max("salary"));
        
        System.out.println(criteria.uniqueResult()); 
    }
    
    @Test
    public void testQBC2(){
        Criteria criteria = session.createCriteria(Employee.class);
        
        //1. AND: 使用 Conjunction 表示
        //Conjunction 本身就是一个 Criterion 对象
        //且其中还可以添加 Criterion 对象
        Conjunction conjunction = Restrictions.conjunction();
        conjunction.add(Restrictions.like("name", "a", MatchMode.ANYWHERE));
        Department dept = new Department();
        dept.setId(80);
        conjunction.add(Restrictions.eq("dept", dept));
       //name like "%a%" and dept=Department [id=80]
        System.out.println(conjunction); 
        
        //2. OR
        Disjunction disjunction = Restrictions.disjunction();
        disjunction.add(Restrictions.ge("salary", 6000F));
        disjunction.add(Restrictions.isNull("email"));
        //salary>=6000 or email is null
        System.out.println(disjunction);    
      
       //上述的两个条件用and连接起来
        criteria.add(disjunction);
        criteria.add(conjunction);
        
        criteria.list();
    }
    
    @Test
    public void testQBC(){
        //1. 创建一个 Criteria 对象
        Criteria criteria = session.createCriteria(Employee.class);
        
        //2. 添加查询条件: 在 QBC 中查询条件使用 Criterion 来表示
        //Criterion 可以通过 Restrictions 的静态方法得到
        criteria.add(Restrictions.eq("email", "SKUMAR"));
        criteria.add(Restrictions.gt("salary", 5000F));
        
        //3. 执行查询
        Employee employee = (Employee) criteria.uniqueResult();
        System.out.println(employee); 
    }

四、本地SQL

    @Test
    public void testNativeSQL(){
        String sql = "INSERT INTO gg_department VALUES(?, ?)";
        Query query = session.createSQLQuery(sql);
        
        query.setInteger(0, 280)
             .setString(1, "ATGUIGU")
             .executeUpdate();
    }

猜你喜欢

转载自blog.csdn.net/fy_java1995/article/details/86570405
今日推荐