Hibernate - QBC和本地SQL对象检索详解

简介: Hibernate - QBC和本地SQL对象检索详解

【1】QBC检索

QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询提供了更加面向对象的功能接口。即使用面向对象的思想实现动态SQL拼接一样的功能,可以理解一下HQL和标准SQL。

这里就需要了解几个接口和实现类。

① Criterion接口

An object-oriented representation of a query criterion that may be used as a restriction in a Criteria query.

查询准则的面向对象表示,可作为Criteria 查询中的规则。

Built-in criterion types are provided by the Restrictions factory class. This interface might be implemented by application classes that define custom restriction criteria.


内置的标准类型由Restrictions 工厂类提供。此接口可以由定义自定义约束标准的应用程序类实现。

其源码如下:

public interface Criterion extends Serializable {
  /**
   * Render the SQL fragment
   *
   * @param criteria The local criteria
   * @param criteriaQuery The overal criteria query
   *
   * @return The generated SQL fragment
   * @throws org.hibernate.HibernateException Problem during rendering.
   */
  public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException;
  /**
   * Return typed values for all parameters in the rendered SQL fragment
   *
   * @param criteria The local criteria
   * @param criteriaQuery The overal criteria query
   *
   * @return The types values (for binding)
   * @throws HibernateException Problem determining types.
   */
  public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException;
}

其实现类如下图所示:


② Restrictions类

该类主要产生Criterion对象,Criteria 通过组合一系列的Criterion对象来检索实体。

方法如下图所示:


③ Criteria接口

继承自CriteriaSpecification,Criteria实现类为CriteriaImpl,Criteria的javadoc如下:

功能说明:Criteria是一个检索entities的简单API,通过组合Criterion对象实现检索功能
<tt>Criteria</tt> is a simplified API for retrieving entities
 * by composing <tt>Criterion</tt> objects. This is a very
 * convenient approach for functionality like "search" screens
 * where there is a variable number of conditions to be placed
 * upon the result set.<br>
 * <br>
 * The <tt>Session</tt> is a factory for <tt>Criteria</tt>.
 * <tt>Criterion</tt> instances are usually obtained via
 * the factory methods on <tt>Restrictions</tt>. eg.
 * <pre>
 * List cats = session.createCriteria(Cat.class)
 *     .add( Restrictions.like("name", "Iz%") )
 *     .add( Restrictions.gt( "weight", new Float(minWeight) ) )
 *     .addOrder( Order.asc("age") )
 *     .list();
 * </pre>
 * 导航对象图检索方式
 * You may navigate associations using <tt>createAlias()</tt> or
 * <tt>createCriteria()</tt>.
 * <pre>
 * List cats = session.createCriteria(Cat.class)
 *     .createCriteria("kittens")
 *         .add( Restrictions.like("name", "Iz%") )
 *     .list();
 * </pre>
 * <pre>
 * List cats = session.createCriteria(Cat.class)
 *     .createAlias("kittens", "kit")
 *     .add( Restrictions.like("kit.name", "Iz%") )
 *     .list();
 * </pre>
 * 报表查询--聚集函数
 * You may specify projection and aggregation using <tt>Projection</tt>
 * instances obtained via the factory methods on <tt>Projections</tt>.
 * <pre>
 * List cats = session.createCriteria(Cat.class)
 *     .setProjection( Projections.projectionList()
 *         .add( Projections.rowCount() )
 *         .add( Projections.avg("weight") )
 *         .add( Projections.max("weight") )
 *         .add( Projections.min("weight") )
 *         .add( Projections.groupProperty("color") )
 *     )
 *     .addOrder( Order.asc("color") )
 *     .list();
 * </pre>

④ Projections

一系列聚集函数的工厂类,用来产生Projection(An object-oriented representation of a query resultset projection in a Criteria query.)对象,其方法如下图所示:


【2】代码测试

① 普通查询

测试代码如下:

  @Test
  public void testQBC(){
    //1. 创建一个 Criteria 对象
    Criteria criteria = session.createCriteria(Employee.class);
    //2. 添加查询条件: 在 QBC 中查询条件使用 Criterion 来表示
    //Criterion 可以通过 Restrictions 的静态方法得到
    criteria.add(Restrictions.eq("email", "AA@QQ.COM"));
    criteria.add(Restrictions.gt("salary", 500F));
    //3. 执行查询
    Employee employee = (Employee) criteria.uniqueResult();
    System.out.println(employee); 
  }

测试结果如下:

Hibernate: 
    select
        this_.ID as ID1_1_0_,
        this_.NAME as NAME2_1_0_,
        this_.SALARY as SALARY3_1_0_,
        this_.EMAIL as EMAIL4_1_0_,
        this_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE this_ 
    where
        this_.EMAIL=? 
        and this_.SALARY>?
Employee [id=1]

上面这种方式与普通HQL查询是等价的。

String HQL = "FROM Employee e where e.email = :email and e.salary > :salary";

② And 和Or查询

And使用Conjunction表示,Or使用Disjunction表示,其均是Junction子类。

测试代码如下:

  @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(1);
    conjunction.add(Restrictions.eq("dept", dept));
    System.out.println(conjunction); 
    //2. OR
    Disjunction disjunction = Restrictions.disjunction();
    disjunction.add(Restrictions.ge("salary", 3000F));
    disjunction.add(Restrictions.isNull("email"));
    System.out.println(disjunction);
    criteria.add(disjunction);
    criteria.add(conjunction);
    List<Employee> list = criteria.list();
    for(Employee employee:list){
      System.out.println(employee);
    }
  }

测试结果如下:

(name like %A% and dept=Department [id=1])
(salary>=3000.0 or email is null)
Hibernate: 
    select
        this_.ID as ID1_1_0_,
        this_.NAME as NAME2_1_0_,
        this_.SALARY as SALARY3_1_0_,
        this_.EMAIL as EMAIL4_1_0_,
        this_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE this_ 
    where
        (
            this_.SALARY>=? 
            or this_.EMAIL is null
        ) 
        and (
            this_.NAME like ? 
            and this_.DEPT_ID=?
        )
Employee [id=1]

③ 对象导航检索测试

测试代码如下:

  @Test
  public void testQBC1(){
     List<Employee> list = session.createCriteria(Employee.class).
//         createCriteria("dept","d")
//         .add( Restrictions.like("d.name", "%A%") )
         createCriteria("dept")
         .add( Restrictions.like("name", "%A%") )
         .list();
     for(Employee employee:list){
        System.out.println(employee);
      }
  }

测试结果如下:

Hibernate: 
    select
        this_.ID as ID1_1_1_,
        this_.NAME as NAME2_1_1_,
        this_.SALARY as SALARY3_1_1_,
        this_.EMAIL as EMAIL4_1_1_,
        this_.DEPT_ID as DEPT_ID5_1_1_,
        department1_.ID as ID1_0_0_,
        department1_.NAME as NAME2_0_0_ 
    from
        GG_EMPLOYEE this_ 
    inner join
        GG_DEPARTMENT department1_ 
            on this_.DEPT_ID=department1_.ID 
    where
        department1_.NAME like ?
Employee [id=1]
Employee [id=2]

④ 聚集函数测试

测试代码如下:

  @Test
  public void testQBC3(){
    Criteria criteria = session.createCriteria(Employee.class);
    //统计查询: 使用 Projection 来表示: 可以由 Projections 的静态方法得到
    criteria.setProjection(Projections.max("salary"));
    System.out.println(criteria.uniqueResult()); 
  }

测试结果如下:

Hibernate: 
    select
        max(this_.SALARY) as y0_ 
    from
        GG_EMPLOYEE this_
10000.0

⑤ 分页和排序

测试代码如下:

  @Test
  public void testQBC4(){
    Criteria criteria = session.createCriteria(Employee.class);
    //1. 添加排序
    criteria.addOrder(Order.asc("salary"));
    criteria.addOrder(Order.desc("email"));
    //2. 添加翻页方法
    int pageSize = 2;
    int pageNo = 2;
    List<Employee> list = criteria.setFirstResult((pageNo - 1) * pageSize)
            .setMaxResults(pageSize)
            .list();
    for(Employee employee:list){
      System.out.println(employee);
    }
  }

测试结果如下:

Hibernate: 
    select
        this_.ID as ID1_1_0_,
        this_.NAME as NAME2_1_0_,
        this_.SALARY as SALARY3_1_0_,
        this_.EMAIL as EMAIL4_1_0_,
        this_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE this_ 
    order by
        this_.SALARY asc,
        this_.EMAIL desc limit ?,
        ?
Employee [id=8]
Employee [id=2]

【3】本地SQL查询

本地SQL查询来完善HQL不能涵盖所有的查询特性,这里主要使用createSQLQuery或createNativeQuery来创建NativeQuery 对象。二者有所区别的是前者创建的query对象在设置参数时索引从0开始,后者从1开始。

测试代码如下:

  @Test
  public void testNativeSQL(){
    String sql = "INSERT INTO gg_department VALUES(?, ?)";
    Query query = session.createSQLQuery(sql);
    int executeUpdate = query.setInteger(0, 15).setString(1, "JANE").executeUpdate();
//    NativeQuery query = session.createNativeQuery(sql);
//    int executeUpdate = query.setInteger(1, 15).setString(2, "JANE").executeUpdate();
    System.out.println(executeUpdate);
  }

测试结果如下:

Hibernate: 
    INSERT 
    INTO
        gg_department
    VALUES
        (?, ?)
1

【4】HQL的更新和删除操作

前面所讲的HQL均是各种查询操作,同样HQL也支持更新和删除(但是不支持插入操作)。

测试代码如下:

  @Test
  public void testHQLUpdate(){
    String hql = "DELETE FROM Department d WHERE d.id = :id";
    session.createQuery(hql).setInteger("id", 280)
                            .executeUpdate();
  }

测试结果如下:

Hibernate: 
    delete 
    from
        GG_DEPARTMENT 
    where
        ID=?

如果尝试使用HQL执行插入操作,则会抛出异常。


目录
相关文章
|
3月前
|
SQL Java 数据库连接
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。
Hibernate 是一款开源 ORM(对象关系映射)框架,封装了 JDBC,允许以面向对象的方式操作数据库,简化了数据访问层的开发。通过映射机制,它可以自动处理对象与数据库表之间的转换,支持主流数据库,提高了代码的可移植性和可维护性。其核心接口包括 SessionFactory、Session 和 Transaction 等,通过它们可以执行数据库的 CRUD 操作。配置方面,需在项目中引入 Hibernate 及数据库驱动依赖,并创建 `hibernate.cfg.xml` 配置文件来设置数据库连接和 Hibernate 行为参数。
47 1
|
3月前
|
SQL 关系型数据库 MySQL
INSERT INTO t_a.tableName SELECT * FROM t_b.tableName 如何通过定义一个list对象,包含多个tableName,循环执行前面的sql,用MySQL的语法写
【8月更文挑战第7天】INSERT INTO t_a.tableName SELECT * FROM t_b.tableName 如何通过定义一个list对象,包含多个tableName,循环执行前面的sql,用MySQL的语法写
41 5
|
3月前
|
Java 数据库连接 数据库
告别繁琐 SQL!Hibernate 入门指南带你轻松玩转 ORM,解锁高效数据库操作新姿势
【8月更文挑战第31天】Hibernate 是一款流行的 Java 持久层框架,简化了对象关系映射(ORM)过程,使开发者能以面向对象的方式进行数据持久化操作而无需直接编写 SQL 语句。本文提供 Hibernate 入门指南,介绍核心概念及示例代码,涵盖依赖引入、配置文件设置、实体类定义、工具类构建及基本 CRUD 操作。通过学习,你将掌握使用 Hibernate 简化数据持久化的技巧,为实际项目应用打下基础。
198 0
|
3月前
|
SQL 数据库 Java
HQL vs SQL:谁将统治数据库查询的未来?揭秘Hibernate的神秘力量!
【8月更文挑战第31天】Hibernate查询语言(HQL)是一种面向对象的查询语言,它模仿了SQL的语法,但操作对象为持久化类及其属性,而非数据库表和列。HQL具有类型安全、易于维护等优点,支持面向对象的高级特性,内置大量函数,可灵活处理查询结果。下面通过示例对比HQL与SQL,展示HQL在实际应用中的优势。例如,HQL查询“从员工表中筛选年龄大于30岁的员工”只需简单地表示为 `FROM Employee e WHERE e.age &gt; 30`,而在SQL中则需明确指定表名和列名。此外,HQL在处理关联查询时也更为直观易懂。然而,对于某些复杂的数据库操作,SQL仍有其独特优势。
59 0
|
3月前
|
API Java 数据库连接
从平凡到卓越:Hibernate Criteria API 让你的数据库查询瞬间高大上,彻底告别复杂SQL!
【8月更文挑战第31天】构建复杂查询是数据库应用开发中的常见需求。Hibernate 的 Criteria API 以其强大和灵活的特点,允许开发者以面向对象的方式构建查询逻辑,同时具备 SQL 的表达力。本文将介绍 Criteria API 的基本用法并通过示例展示其实际应用。此 API 通过 API 构建查询条件而非直接编写查询语句,提高了代码的可读性和安全性。无论是简单的条件过滤还是复杂的分页和连接查询,Criteria API 均能胜任,有助于提升开发效率和应用的健壮性。
123 0
|
3月前
|
SQL Java 数据库连接
|
3月前
|
Java 数据库连接 数据库
|
3月前
|
Java 数据库连接 数据库
|
3月前
|
SQL 缓存 Java
如何在 Hibernate 中启用 SQL 日志记录?
【8月更文挑战第21天】
129 0