Hibernate检索方式
导航对象图检索方式
根据已经加载的对象导航到其他对象
样例:
Order order=session.get(Order.class, 1);
order.getCustomer();
OID 检索方式: 按照对象的 OID 来检索对象
Order order=session.get(Order.class, 1);
order.getCustomer();
HQL 检索方式: 使用面向对象的 HQL 查询语言
测试案例:
1)永久化类
public class Employee {
private Integer id;
private String name;
private float salary;
private String email;
private Department dept;}
public class Department {
private Integer id;
private String name;
private Set<Employee> emps=new HashSet<>();}
2)实体关系配置表
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2020??4??19?? ????5:15:24 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.atguigu.hibernate.entities.Department" table="GG_DEPARTMENT">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
<key>
<column name="DEPT_ID"/>
</key>
<one-to-many class="com.atguigu.hibernate.entities.Employee" />
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2020??4??19?? ????5:15:24 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.atguigu.hibernate.entities.Employee" table="GG_EMPLOYEE">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="salary" type="float">
<column name="SALARY" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<many-to-one name="dept" class="com.atguigu.hibernate.entities.Department">
<column name="DEPT_ID" />
</many-to-one>
</class>
</hibernate-mapping>
##检索步骤
1)通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句.HQL查询语句中可以包含命名参数
2)动态绑定参数
3)调用Query相关方法执行查询语句
Qurey接口支持方法链编程风格,它的setXxx()方法返回自身实例,而不是void类型
绑定参数查询
Hibernate的参数绑定机制依赖于JDBCAPI中的PreparedStatement的预定义SQL语句功能。
按参数名字绑定
在HQL查询语句中定义命名参数,命名参数以“:”开头。
String hql="From Employee e WHERE e.salary> :salar ";
//String hql="From Employee e";
Query<Employee> query=session.createQuery(hql);
query.setFloat("salar", 200.0f);
//query.setParameter("salar", 200.0f);也可以运行
List<Employee> emps=query.list();
System.out.println(emps);
按参数位置绑定
在HQL查询语句中用“?”来定义参数位置
String hql="From Employee e WHERE e.salary> ? ";
Query<Employee> query=session.createQuery(hql);
//query.setParameter(0, 200.0f);报错
//query.setFloat(0, 200.0f);报错
在hibernate测试发现,参数查询设置参数对应的取值均报错。
分页查询
1)setFirstResult(intfirstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0.默认情况下,Query从查询结果中的第一个对象开始检索
2)setMaxResults(intmaxResults):设定一次最多检索出的对象的数目.在默认情况下,Query和Criteria接口检索出查询结果中所有的对象
String hql="From Employee";
Query query=session.createQuery(hql);
int pageNo=3;
int pageSize=5;
List<Employee> emps=query.setFirstResult((pageNo-1)*pageSize).setMaxResults(pageSize).list();
System.out.println(emps);
在映射文件中定义命名查询语句
1)Hibernate 允许在映射文件中定义字符串形式的查询语句.
2)<query> 元素用于定义一个 HQL 查询语句, 它和 元素并列.
3)在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象
示例代码:
1)实体关系文件中配置
<query name="salaryEmps">
<![CDATA[FROM Employee e where e.salary>:minsal and e.salary<:maxSal]]>
</query>
</hibernate-mapping>
2)代码测试
public void test() {
Query query=session.getNamedQuery("salaryEmps");
List<Employee> emps=query.setParameter("minsal", 800f).setParameter("maxSal", 6000f).list();
System.out.println(emps.size());
}
投影查询
1)投影查询:查询结果仅包含实体的部分属性.通过SELECT关键字实现
2)Query的list()方法返回的集合中包含的是数组类型的元素,每个对象数组代表查询结果的一条记录
public void test() {
String hql="select e.email,e.salary 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));
}
}
3)可以在持久化
类中定义一个对象的构造器来包装投影查询返回的记录,使程序代码能完全运用面向对象的语义来访问查询结果集.
public void test() {
String hql="select new Employee(e.name,e.salary,e.dept) from Employee e where e.dept=:dept";
Query query=session.createQuery(hql);
Department dept=new Department();
dept.setId(10);
List<Employee>result=query.setEntity("dept", dept).list();
for(Employee emp:result) {
System.out.println(emp.toString());
}
}
4)可以通过DISTINCT关键字来保证查询结果不会返回重复元素
public void test() {
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", 800);
List<Object []> result = query.list();
for(Object [] objs: result){
System.out.println(Arrays.asList(objs));
}
}
HQL(迫切)左外连接
在mysql语句中左外连接和迫切左外连接是没有区别的,但是在hibernate框架中是有区别的。
含义:让左表和右表进行连接,左边的表必然出现,如果右边中没有满足条件的连接出现,左表数据仍然显示,只是连接的的数据为空。
迫切左外连接
1)LEFT JOINFETCH关键字表示迫切左外连接检索策略.
2)list()方法返回的集合中存放实体对象的引用,每个Department对象关联的Employee集合都被初始化,存放所有关联的Employee的实体对象.
3)查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素
public void test() {
String hql="SELECT DISTINCT d From Department d LEFT JOIN FETCH d.emps";
//DISTINCT用于去除重复的Department,如果不加返回的记录数为实际的sql查询的返回记录数
//此处的DISTINCT会在sql语句中出现,但是实际上在SQL语句上面没有明显的用处
//因为sql语句部门+机构不会照成重复的sql语句
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());
}
}
public void test() {
String hql="From Department d LEFT 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());
}
}
左外连接
1)LEFT JOIN关键字表示左外连接查询.
2)list()方法返回的集合中存放的是对象数组类型
3)根据配置文件来决定Employee集合的检索策略.
4)如果希望list()方法返回的集合中仅包含Department对象,可以在HQL查询语句中使用SELECT关键字
public void test() {
String hql="SELECT DISTINCT d From Department d LEFT JOIN d.emps";
//DISTINCT去除重复,select d是为了强制使得返回为Department类型,此处默认返回为object
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());
//element并没有完成初始化
}
}
HQL(迫切)内连接
迫切内连接
1)INNER JOIN FETCH关键字表示迫切内连接,也可以省略INNER关键字
2)list()方法返回的集合中存放Department对象的引用,每个Department对象的Employee集合都被初始化,存放所有关联的Employee对象
内连接
1)INNER JOIN关键字表示内连接,也可以省略INNER关键字
2)list()方法的集合中存放的每个元素对应查询结果的一条记录,每个元素都是对象数组类型
3)如果希望list()方法的返回的集合仅包含Department对象,可以在HQL查询语句中使用SELECT关键字
关联级别运行时的检索策略
1)如果在HQL中没有显式指定检索策略,将使用映射文件配置的检索策略.
2)HQL会忽略映射文件中设置的迫切左外连接检索策略,如果希望HQL采用迫切左外连接策略,就必须在HQL查询语句中显式的指定它
3)若在HQL代码中显式指定了检索策略,就会覆盖映射文件中配置的检索策略
QBC 检索方式
使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口。
QBC查询就是通过使用Hibernate提供的QueryByCriteriaAPI来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口
1)测试示例
public void test() {
Criteria criteria=session.createCriteria(Employee.class);
criteria.add(Restrictions.eq("id",15));
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_.ID=?
Employee [id=15]
测试代码2
public void test() {
Criteria criteria=session.createCriteria(Employee.class);
//and
Conjunction conjunction=Restrictions.conjunction();
conjunction.add(Restrictions.ilike("name", "a",MatchMode.ANYWHERE));
Department dept=new Department();
dept.setId(80);
conjunction.add(Restrictions.eq("dept",dept));
System.out.println(conjunction);
//or
Disjunction disjunction=Restrictions.disjunction();
disjunction.add(Restrictions.ge("salary",6000f));
disjunction.add(Restrictions.isNull("email"));
criteria.add(disjunction);
criteria.add(conjunction);
criteria.list();
}
测试结果
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 (
lower(this_.NAME) like ?
and this_.DEPT_ID=?
)
测试代码
public void test() {
Criteria criteria=session.createCriteria(Employee.class);
criteria.setProjection(Projections.max("salary"));
System.out.println(criteria.uniqueResult());
}
测试结果
Hibernate:
select
max(this_.SALARY) as y0_
from
GG_EMPLOYEE this_
12000.0
测试代码:
public void test() {
Criteria criteria=session.createCriteria(Employee.class);
criteria.addOrder(Order.asc("salary"));
criteria.addOrder(Order.desc("email"));
int pageSize=5;
int pageNo=3;
criteria.setFirstResult((pageNo-1)*pageSize)
.setMaxResults(pageSize)
.list();
}
测试结果:
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 ?,
?
本地SQL检索方式
本地SQL查询来完善HQL不能涵盖所有的查询特性
public void test() {
String sql="Insert into gg_department values(:value1,:value2)";
Query query=session.createSQLQuery(sql);
query.setParameter("value1", 280)
.setParameter("value2", "ATGUIGU").executeUpdate();
}