Hibernate 配备了一种非常强大的查询语言,这种语言看上去很像 SQL。但是不要被语法结构上的相似所迷惑,HQL 是非常有意识的被设计为完全面向对象的查询,它可以理解如继承、多态和关联之类的概念。
基本规则
- HQL语法类似于SQL,也是一种select from结构的语句。但是他后面跟的不是表名和字段名,而是类名和属性名。
- HQL基本查询语法跟SQL很类似
- HQL大小写不敏感。但是,设计java类名、包名、属性名时大小写敏感。
- 包名的使用情况。比如:如果注册的实体类Emp只有一个类,那么查询时可以不加包名,hibernate会自动检索到Emp类。但是如果注册多个实体类,名字都叫Emp。此时就要增加包名来区别多个实体类。
第一个HQL查询
1 package com.qcf.test; 2 3 import java.util.List; 4 5 6 import org.hibernate.Query; 7 import org.hibernate.Session; 8 import org.hibernate.SessionFactory; 9 import org.hibernate.Transaction; 10 import org.hibernate.cfg.Configuration; 11 12 import com.qcf.po.User; 13 14 public class TestHiber { 15 public static void main(String[] args) { 16 //读取配置文件中的信息 17 Configuration con=new Configuration().configure(); 18 //获取sessionFactory对象 19 SessionFactory factory=con.buildSessionFactory(); 20 //获取Session对象 21 Session session=factory.openSession(); 22 String hql="from User"; 23 //创建HQL查询 24 Query query= session.createQuery(hql); 25 List list=query.list(); 26 //对查询的结果进行遍历 27 for (int i = 0; i < list.size(); i++) { 28 User user=(User) list.get(i); 29 System.out.println(user.getName()); 30 } 31 32 session.close(); 33 } 34 }
查询结果:
根据返回类型划分HQL查询
1、单个对象
在这里提醒一下,这个hql意识统计数据库的记录数,一般我们都知道count(1) 要比count(*) 快多了,但是这里必须使用count(*) 使用count(1)就会报错!
1 package com.qcf.test; 2 3 import java.util.List; 4 5 6 import org.hibernate.Query; 7 import org.hibernate.Session; 8 import org.hibernate.SessionFactory; 9 import org.hibernate.Transaction; 10 import org.hibernate.cfg.Configuration; 11 12 import com.qcf.po.User; 13 14 public class TestHiber { 15 public static void main(String[] args) { 16 //读取配置文件中的信息 17 Configuration con=new Configuration().configure(); 18 //获取sessionFactory对象 19 SessionFactory factory=con.buildSessionFactory(); 20 //获取Session对象 21 Session session=factory.openSession(); 22 String hql="select count(*) from User"; 23 //创建HQL查询 24 Query query= session.createQuery(hql); 25 Number n=(Number) query.uniqueResult(); 26 System.out.println(n.intValue()); 27 28 session.close(); 29 } 30 }
2、List集合
参考第一个HQL查询中的内容!
3、Object[]数组
有时候,我们不需要讲实体类的所有属性查找出来,只需要查找部分属性。这时,可以将返回的内容放入Object[]中,而不是实体对象中。
1 String hql="select u.name,u.age from User u"; 2 //创建HQL查询 3 Query q= session.createQuery(hql); 4 List<Object[]> list=q.list(); 5 for (int i = 0; i < list.size(); i++) { 6 Object[] os=list.get(i); 7 System.out.println("用户名是:"+os[0]+"年龄是:"+os[1]); 8 }
显示结果:
Hibernate: select user0_.username as col_0_0_, user0_.userage as col_1_0_ from user user0_
用户名是:哈哈年龄是:18
用户名是:三个年龄是:18
用户名是:张三年龄是:18
用户名是:李四年龄是:18
用户名是:王五年龄是:18
用户名是:张柳 年龄是:18
4、Map集合
我们也可以将查询后的结果放到map中
1 String hql="select new map(u.name as name,u.age as age) from User u"; 2 //创建HQL查询 3 Query q= session.createQuery(hql); 4 List<Map> list=q.list(); 5 for (int i = 0; i < list.size(); i++) { 6 Map map=list.get(i); 7 System.out.println("用户名"+map.get("name")+"年龄"+map.get("age")); 8 } 9 session.close();
显示结果:
Hibernate: select user0_.username as col_0_0_, user0_.userage as col_1_0_ from user user0_
用户名哈哈年龄18
用户名三个年龄18
用户名张三年龄18
用户名李四年龄18
用户名王五年龄18
用户名张柳 年龄18
5、实体对象
对于只查询部分属性的情况,Object数组、Map都很方便。实际上,我们也可以通过构造方法,将查出的数据直接封装到实体对象中。
1 新增构造方法: 2 public Emp(Short empno, String ename) { 3 super(); 4 this.empno = empno; 5 this.ename = ename; 6 } 7 String hql = "select new Emp(e.empno,e.ename) from Emp e "; 8 Query q = session.createQuery(hql); 9 10 List<Emp> list = q.list(); 11 for(int i=0;i<list.size();i++){ 12 Emp e = list.get(i); 13 System.out.println("雇员编号:"+e.getEmpno()+"-雇员名字"+e.getEname()); 14 }
6、Where子句和参数传递
1 // String hql = "from Emp where ename=?"; 2 String hql = "from Emp where ename=:ename"; //使用参数名称动态绑定!(推荐使用!) 3 Query q = session.createQuery(hql); 4 // q.setString(0, "SMITH"); //参数索引从0开始计数,而不像jdbc一样从1开始。 5 q.setString("ename", "SMITH"); 6 List list = q.list(); 7 for(int i=0;i<list.size();i++){ 8 Emp c = (Emp) list.get(i); 9 System.out.println(c.getEname()); 10 }
7、HQL分页查询
分页显示是项目中必不可少的功能,不同的数据库有不同的分页方式,hibernate替我们屏蔽了数据库中之间的差异。我们通过如下简单的代码即可实现分页功能(如果分页的原 理和做法忘记了,可以参考之前讲授的项目内容)。
1 String hql = "from Emp"; 2 Query q = session.createQuery(hql); 3 q.setFirstResult(0); //从第几条开始取数据 4 q.setMaxResults(10); //设置每页最多显示记录的个数 5 6 List list = q.list(); 7 for(int i=0;i<list.size();i++){ 8 Emp c = (Emp) list.get(i); 9 System.out.println(c.getEname()); 10 }
8、跨表查询和对象导航
SQL中复杂的表连接查询,跨表操作。在HQL中进行了相当的简化,我们只需要简单的使用属性即可,类似于我们前面学过的EL表达式。这样,我们可以用简单的代码写出比较 复杂的查询。
1 String hql = "from Emp e where e.dept.deptno=? "; 2 Query q = session.createQuery(hql); 3 q.setInteger(0, 10);
9、Join(内连接、外连接)
SQL中我们有内连接、右外连接、左外连接、全外连接,在HQL中我们也有这些概念。不过,有如下几点不一致:
- 如果两个实体类之间没有任何关系,那么不能使用join
- 由于只有两个实体类之间有关联关系才能使用join,因此不需要像SQL那样通过on指明连接条件。
代码示例如下:
1 String hql = "select e.ename,d.dname from Emp e left join e.dept d "; 2 3 Query q = session.createQuery(hql);
10、SQL原生查询(Native SQL)
有时候HQL可能不能满足我们的要求。我们需要使用原始的SQL来完成我们的功能。我们可以通过如下方式,在hibernate中使用SQL查询:
1 String sql = "select ename,sal from emp where empno=:id"; 2 SQLQuery q = session.createSQLQuery(sql); 3 q.setInteger("id", 7369); 4 List list = q.list(); //返回的结果为List<Object[]> 5 for(int i=0;i<list.size();i++){ 6 Object[] c = (Object[]) list.get(i); 7 System.out.println(c[0]+"-"+c[1]); 8 } 9 String sql = "select * from emp where empno=:id"; 10 SQLQuery q = session.createSQLQuery(sql); 11 q.setInteger("id", 7369); 12 q.addEntity(Emp.class); 13 List<Emp> list = q.list(); 14 for(int i=0;i<list.size();i++){ 15 Emp c = list.get(i); 16 System.out.println(c.getEname()+"-"+c.getSal()); 17 }