HQL的检索方式
HQL是面向持久化类的,所以需要查询表的字段都要用持久化类指定
例如
String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept";
Query query = session.createQuery(hql);
我们要查询表Employees的Email字段,但是我们不能直接select Email from empolyees,而是要通过持久化类来指定
SELECT e.email FROM Employee e
这也是HQL好处之一,面向持久化类,不面向数据裤,进而无论你换了其它什么数据库,语句还是可以正常运行
这一点要谨记
1分页查询:
setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索 (setFirstResult=BeginData,,就是从第几条记录开始查询)
setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象 有了这两个,不用管底层数据库是怎样实现的 setMaxResults=pageSize(设定了每页显示的记录数)
example:
@Test public void testPageQuery(){ String hql = "FROM Employee"; Query query = session.createQuery(hql); int pageNo = 22; int pageSize = 5; //显示第21页的记录,当setMaxResults设置值后,也就规定了数据表的记录分为多少页了 List<Employee> emps =query.setFirstResult((pageNo - 1) * pageSize) .setMaxResults(pageSize) .list(); System.out.println(emps); }
2在映射文件中定义命名查询语句
Hibernate 允许在映射文件中定义字符串形式的查询语句.
<query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列. 因为了是在xml文件中定义,为了尽量不引起歧义,所以HQL语句尽量保存在<![cdata[这里]]>这一点需要特别的注意 示例:
<query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>
在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象.
@Test public void testNamedQuery(){ Query query = session.getNamedQuery("salaryEmps");//取得在.hbm.xml文件定义的HQL语句 List<Employee> emps = query.setFloat("minSal", 5000) .setFloat("maxSal", 10000) .list(); System.out.println(emps.size()); }
3投影查询
投影查询: 查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.,就是查询部分属性(select那里声明,与SQL一样)
1做法一:Query 的 list() 方法返回的是集合数组类型的元素(就是list方法返回了一个list对象), 每个对象数组代表查询结果的一条记录(所以必须用list<Objec[]>来存储)
example:
@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对象,所以要用list<object []>数组存储起来 List<Object[]> result = query.setEntity("dept", dept) .list(); for(Object [] objs: result){ System.out.println(Arrays.asList(objs)); } }
2做法二:可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录,也就是说咋们返回多少个参数,就定义一个该对象对应的参数构造器,把返回的数据封装到一个对象里,这样更加容易遍历 使程序代码能完全运用面向对象的语义来访问查询结果集.
example:
@Test public void testFieldQuery2(){
//把返回的参数都封装给一个employee对象,但是前提必须要有对应的构造器 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()); } }
可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素
4报表查询
报表查询(就是对数据排序,分组,进行一定的筛选)
报表查询用于对数据分组和统计, 与 SQL 一样, HQL 利用 GROUP BY 关键字对数据分组, 用 HAVING 关键字对分组数据设定约束条件.(这些关键字的用法和SQL一样所以没啥好说的)
在 HQL 查询语句中可以调用以下聚集函数 count() min() max() sum() avg()
example:
@Test public void testGroupBy(){
//用"+"号连接HQL语句时记得要用双引号(""), 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)); } }
5(迫切)左外连接
左外连接:显示join左边表的所有数据,也就是from 那个表,比如 from student left join teacher on s_id=t_id显示student的所有数据,teacher中不符合条件的数据将被显示为null
迫切左外连接: (推荐在多对一和一对一查询数据时使用这个)
1)LEFT JOIN FETCH 关键字表示迫切左外连接检索策略. (就是fetch取值为join)
2)list() 方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee 集合都被初始化, 存放所有关联的Employee 的实体对象.
3)查询结果中可能会包含重复元素, 可以通过一个 HashSet或者 DISTINCT 来过滤重复元素
左外连接:
1)LEFT JOIN 关键字表示左外连接查询.
2)list() 方法返回的集合中存放的是对象数组类型
(集合对象是被初始化了,但是集合对象的对象没有被初始化,)
例如list<department>,而department中又有一个employee对象,此时department对象已经被初始化了,而employee对象并没有被初始化
也可以这样理解连接的右表对象并没有被初始化,例如:
from department left join employee on d_id=e_id
也就说此时department对象被初始化了,employee对象没有被初始化,
3)根据配置文件来决定 Employee 集合的检索策略.(fetch的取值)
4)如果希望 list() 方法返回的集合中仅包含 Department 对象, 可以在HQL 查询语句中使用 SELECT 关键字
6(迫切)内连接
内连接:两个表的记录同时符合连接条件才会被显示
例如:from student left join teacher on s_id=t_id
student和teacher的记录同时符合条件才会被显示
迫切内连接:
INNER JOIN FETCH 关键字表示迫切内连接, 也可以省略 INNER 关键字
list() 方法返回的集合中存放 Department 对象的引用, 每个 Department 对象的 Employee 集合都被初始化, 存放所有关联的 Employee 对象
内连接:
INNER JOIN 关键字表示内连接, 也可以省略 INNER 关键字
list() 方法的集合中存放的每个元素对应查询结果的一条记录, 每个元素都是对象数组类型 如果希望 list() 方法的返回的集合仅包含 Department 对象, 可以在 HQL 查询语句中使用 SELECT 关键字
关联级别策略
如果在 HQL 中没有显式指定检索策略, 将使用映射文件配置的检索策略. HQL 会忽略映射文件中设置的迫切左外连接检索策略, 如果希望 HQL 采用迫切左外连接策略, 就必须在 HQL 查询语句中显式的指定它 若在 HQL 代码中显式指定了检索策略, 就会覆盖映射文件中配置的检索策略