现在的位置: 首页 > 综合 > 正文

HQL的基本语法

2013年10月03日 ⁄ 综合 ⁄ 共 6875字 ⁄ 字号 评论关闭

 HQL检索方式

 

HQL(Hibernate Query Language)查询语言是面向对象的查询语言,也是在Hibernate中最常用的。其语法和SQL语法有些相似,功能十分强大,几乎支持除特殊SQL扩展外的所有查询功能。此种查询方式为Hibernate官方推荐的标准查询方式。

 HQL的基本语法

HQL检索方式与SQL相似,使用方法基本相同;但HQL是面向对象查询语言,它查询的目标为对象,而SQL查询的目标则为数据表;除此之外,在书写HQL语句时要注意,它对大小写是敏感的。其基本语法如下:

select “属性名” from “对象”

where “条件”

group by “属性名” having “分组条件”

order by “属性名” desc/asc

从上述基本语法可以看出,HQL与SQL的用法基本是一样的;但要注意,在使用HQL时在头脑中一定要有对象的概念。

例如:

select * from User u where u.id>10 order by u.id desc

此语句将查询User对象所对应数据表中的记录,条件为id大于10,并将返回的结果集按id的降序进行排序,语句中的User为对象。

在HQL查询语句中,同样支持DML风格的语句,如update语句、delete语句,其使用方法与上述方法基本相同。不过,由于Hibernate缓存的存在,使用DML语句进行操作可能会造成与Hibernate缓存不同步的情况,从而导致脏数据的产生,所以在使用过程中应该尽量避免使用DML语句操作数据。

 实体对象与动态实例化对象查询

þ      实体对象查询

在HQL查询语句中,如果直接查询实体对象,不能使用select *子句的形式,但可以使用“from 对象”的形式进行查询。

例如:

from User

上述HQL语句意味着查询User对象所对应数据表中的所有记录,使用此语句可获取已封装好的User对象的集合。

þ      动态实例化对象查询

在数据查询过程中,当数据表中存在大量的字段,如果通过“select *”的形式将所有字段都查询出来,将会对性能方面造成一定的影响。在HQL中,可以通过只查询所需要的属性进行查询。

例如:

select id, name from User

上述HQL语句只查询了User对象中的id与name属性,可以避免查询数据表中的所有字段而带来的性能方面的问题。但在Hibernate中,此语句返回的却是Object类型的数组,它失去了原有的对象状态,破坏了数据的封装性。要解决此问题,可以通过动态实例化对象来查询。

例如:

select new User(id,name) from User

这种查询方式通过new关键字对实体对象动态实例化,它可以对数据作出封装,既不失去数据的封装性,又可提高查询的效率。

例15.13  查询User对象中的所有数据。在UserDao类中编写findUser()方法,用于查询所有User对象。其关键代码如下:(实例位置:光盘\TM\Instances\15.13)

//获取Session

session = HibernateUtil.getSession();

session.beginTransaction();    //开启事务

String hql = "from User";        //HQL语句

//创建Query对象

Query query = session.createQuery(hql);

list = query.list();          //获取查询结果集

//提交事务

session.getTransaction().commit();

HQL查询方式使用Query进行查询,其list()方法返回查询的结果,实例中将其输出到网页之中,其运行结果如图15.19所示。

 

图15.19  实例运行结果

 条件查询与别名的使用

对于条件查询,在HQL语句中通过where子句来实现。

例如:

from User where id = 1

此句用于实现查询id为1的User对象。

为了明确区分对象与对象中的属性,HQL提供了以下使用对象别名的方法。

þ      第一种方法:

from User u where u.id = 1

þ      第二种方法:

from User as u where u.id = 1

第二种方法与第一种方法相比,多了一个关键字as。

 HQL语句的动态赋值

在JDBC编程中,PreparedStatement对象为开发提供了方便,它不但可为SQL语句进行动态赋值,而且可以避免SQL的注入式攻击;此外,由于它使用了SQL的缓存技术,还可以提高SQL语句的执行效率。在HQL查询语言中,也提供了类似的方法,其实现方式主要有两种。

þ      “?”号代表参数

此种方式与PreparedStatement极其相似,通过Query对象的setParameter()方法进行赋值,在HQL语句中以“?”号代表参数。如查询id为3的User对象,可以使用以下方法。

//HQL语句

String hql = "from User u where u.id = ?";        

//创建Query对象

Query query = session.createQuery(hql);

//HQL参数赋值

query = query.setParameter(0, 3);

//获取查询结果集

list = query.list();

þ      自定义参数名称

此种方式也通过Query对象的setParameter()方法进行赋值,但HQL语句中的参数可以自定义,它通过“:”号与自定义参数名组合的方法实现。如查询id为3的User对象,可以使用以下方法。

//HQL语句

String hql = "from User u where u.id = :userId";        

//创建Query对象

Query query = session.createQuery(hql);

//HQL参数赋值

query = query.setParameter("userId", 3);

//获取查询结果集

list = query.list();

 对象导航查询

HQL查询语言符合Java程序员的编程习惯,查询过程都以对象的方式进行操作,当一个对象与另一个对象存在依赖关系时,可以通过“.”符号进行导航。

例15.14  对象导航查询。(实例位置:光盘\TM\Instances\15.14)

编写名为Test的类,在此类中进行对象导航查询。其关键代码如下:

//获取Session

session = HibernateUtil.getSession();

//开启事务

session.beginTransaction();

//HQL查询语句

String hql = "from Medicine m where m.category.name = ?";

//创建Query对象并对HQL动态赋值

Query query = session.createQuery(hql)

                                        .setParameter(0, "感冒用药");

//获取查询结果集

List<Medicine> list = query.list();

//循环输出类别"感冒用药"中的药品名称

for(Medicine m : list){

System.out.println("感冒用药: " + m.getName());

}

//提交事务

session.getTransaction().commit();

在本例中,查询了药品类别名称为“感冒用药”中的所有药品,并将药品的名称输出到控制台。其中使用“.”符号进行导航,其HQL语句中的m.category.name代表药品类别的名称。实例运行结果如图15.20所示。

 

图15.20  实例运行结果

 排序查询

在获取数据结果集时,经常要对查询的结果集进行排序操作,以使其条理清晰、一目了然。HQL查询语言同样提供了此功能,主要是通过order by子句来实现,对于排序类型使用asc、desc关键字。

例如:

from User u order by id asc

此HQL语句可以实现查询User对象,并按id的升序排序。

例如:

from User u order by age desc

此HQL语句可以实现查询User对象,并按年龄的降序排序。

 聚合函数

在HQL查询语言中,支持常用聚合函数的使用,如sum、count、max、min等,其使用方法与SQL中基本相同。如查询数据表中的记录,使用count(*)即可。

例如:

select count(*) from User u

此HQL语句可以实现查询User对象所对应的数据表中的记录数。

例如:

select max(u.id) from User u

此HQL语句可以实现查询User对象所对应的数据表中的最大id值。

 分组操作

在HQL查询语言中,通常使用group by子句进行分组操作,其使用方法与SQL相似;此外,它也可以使用having关键字设置分组的条件。

例15.15  编写一个名为Test的类,在main()方法中通过分组操作统计部门人数。其关键代码如下:(实例位置:光盘\TM\Instances\15.15)

//获取Session

session = HibernateUtil.getSession();

session.beginTransaction(); //开启事务

//HQL语句

String hql = "select u.dept,count(*) from User u group by u.dept";

//创建Query对象

Query query = session.createQuery(hql);

//获取结果集

List<Object[]> list = query.list();

//循环输出部门名称及人数

for (Object[] obj : list) {

System.out.print("部门: " + obj[0] + "---");

System.out.println("人数: " + obj[1]);

}

//提交事务

session.getTransaction().commit();

在上述HQL语句中,count(*)用于统计部门的人数,group by u.dept表示通过部门进行分组。实例运行前,数据表中的数据如图15.21所示;实例运行后将输出部门的人数,如图15.22所示。

  

图15.21  员工信息表数据 

    

                            图15.22  实例运行结果

 对日期时间的处理

在HQL查询语言中,提供了多种对日期时间进行查询的方法,如可以使用“=”号进行时间的精确匹配,使用between…and子句查询指定的时间范围;此外,在HQL语句中还可以使用date_format()函数进行时间的模糊查询。

例15.16  编写一个名为Test的类,在main()方法中查询1984年1月出生的用户。其关键代码如下:(实例位置:光盘\TM\Instances\15.16)

//获取Session

session = HibernateUtil.getSession();

session.beginTransaction(); // 开启事务

//HQL语句

String hql = "from User u where date_format(u.birth,'%Y-%m') = ?";

//创建Query对象

Query query = session.createQuery(hql)

                              .setParameter(0, "1984-01");

//获取结果集

List<User> list = query.list();

System.out.println("1984年1月出生的用户有:");

//循环输出1984年1月出生的用户姓名及出生日期

for (User user : list) {

System.out.print("姓名: " + user.getName() + "\t");

System.out.println("出生日期: " + user.getBirth());

}

//提交事务

session.getTransaction().commit();

在上述HQL语句中,date_format(u.birth,'%Y-%m')用于格式化用户的出生日期。在实例运行前,数据表中的数据如图15.21所示;实例运行后将输出1984年1月出生的用户,如图15.23所示。

 

图15.23  实例运行结果

 联合查询

在对多表进行查询时,经常用到联合查询,通过它可以方便地对多表中的数据进行快速检索。与SQL相同,HQL同样支持这种机制。在HQL中,可以使用内连接、外连接及全连接对多表进行联合操作,其使用方式如表15.2所示。

表15.2  HQL联合查询方式说明

查 询 方 式

说   

内连接

使用inner join子句,可以简写为join

左外连接

使用left outer join子句,可以简写为left join

右外连接

使用right outer join子句,可以简写为right join

全连接

使用full join子句

在联合查询中,如果需要设置额外的条件,使用HQL的关键字with进行设置。

例如:

from Student s left join s.classes c with c.id > 10

例15.17  使用内连接查询药品信息及所属类别的名称。(实例位置:光盘\TM\Instances\15.17)

在本例中编写药品数据库操作类MedDao,在此类中通过findMedAndCategory()方法进行内连接查询。其关键代码如下:

public List<Object[]> findMedAndCategory() {

Session session = null; //声明Session对象

List<Object[]> list = null;

try {

           //获取Session

           session = HibernateUtil.getSession();

           //开启事务

           session.beginTransaction();

           //HQL查询语句

           String hql = "select m.id,m.name,m.price,m.factoryAdd,c.name from Medicine m inner join m.category c";

           //创建Query对象并获取结果集

           list = session.createQuery(hql)

                                         .list();

           //提交事务

           session.getTransaction().commit();

} catch (Exception e) {

           e.printStackTrace();

           //出错将回滚事务

           session.getTransaction().rollback();

} finally {

           //关闭Session对象

           HibernateUtil.closeSession(session);

}

return list;

}

在上述HQL语句中,m.category c是指药品对象的所属类别。实例运行结果如图15.24所示。

 

图15.24  实例运行结果

 子查询

功能强大的HQL查询语言,几乎支持除SQL中一些特殊扩展功能外的所有查询方式,对于子查询在HQL中也是可以使用的。

例15.18  使用子查询查询药品对象中最贵的药品名称。(实例位置:光盘\TM\Instances\15.18)

编写名为Test的类,在此类中通过main()方法进行查询。其关键代码如下:

//获取Session

session = HibernateUtil.getSession();

session.beginTransaction(); //开启事务

// HQL语句

String hql = "select med.name from Medicine med where med.price = (select max(price) from Medicine)";

//获取结果集

List<String> list = session.createQuery(hql).list();

//循环输出最贵的药品

for (String name : list) {

System.out.println("最贵的药品为: " + name);

}

//提交事务

session.getTransaction().commit();

在上述HQL语句中,其子句select max(price) from Medicine用于查询药品对象中最贵的价格,然后查询价格等于此价格的药品的名称,其运行结果如图15.25所示。

 

图15.25  实例运行结果

抱歉!评论已关闭.