Hibernate级联查找
一 、工作目的:
本例主要演示在SSH架构下实现hibernate的级联查找,通过配置文件将多张有关联的表联系在一起,只需一次检索数据库便可查询多表记录,好处是避免多次单表查找影响系统效率,不过目前数据库设计一般不推荐添加外键,而通过配置hibernate级联查找,会在数据库中自动生成索引、外键,使用时需要根据具体场景慎重选择。
二 、开发环境:
Myeclipse 8.5+Mysql 5.0+Tomcat 6.0+JDK 1.6
三、详细步骤:
1.数据库表的设计
staff 表:
department 表:
Staff表的DepartId字段对应Department表的DepartmentId字段。使用中,通过条件查找Staff表示,同时查询出对应的Department表的内容。
2.staff.xml 配置文件
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.model.Staff" table="staff" catalog="hibernate_cascade_query">
<id name="id" type="java.lang.Integer">
<column name="Id" />
<generator class="identity" />
</id>
<property name="employeeName" type="java.lang.String">
<column name="EmployeeName" length="20" not-null="true"/>
</property>
<property name="departId" type="java.lang.Integer">
<column name="DepartId" not-null="true" />
</property>
<property name="address" type="java.lang.String">
<column name="Address" length="20" />
</property>
<many-to-one name="department" cascade="none" insert="false" update="false" lazy="false" class="com.model.Department" column="departId"></many-to-one>
</class>
</hibernate-mapping></span>
Staff与Department属于多对一的关系,因此用<many-to-one>标签,其属性值简介如下:
name:用于确定该属性名
cascade:主记录表到子记录表的级联行为(save、delete、update..),all表示包括所有。
class:指定要关联的表。
property-ref:主记录表的主键与关联表的某列的关联,当不指定该属性,默认主表的主键与关联表的主键对应。
fetch:抓取策略,access:访问策略,lazy:延迟加载特性,这些属性可选。
3.staff.java 类
4.DaoImp 层的编写
4.1 左连接
public List<Object> leftJoin(String staffName) {
Session session=sessionFactory.getCurrentSession();
try{
Transaction tx=session.beginTransaction();
String hql="from Staff staff LEFT JOIN staff.department where staff.employeeName='"+staffName+"'";
List<Object> list=session.createQuery(hql).list();
tx.commit();
}catch(Exception e){
e.printStackTrace();
session.close();
<span style="font-size:14px;"> }
</span>
需要注意是hql语句的书写:String hql="from Staffstaff LEFT JOIN staff.department where staff.employeeName='"+staffName+"'";中staff.department对应配置文件里面name属性值相同。
查找结果如下:
返回的Object数组里面存放根据条件查找出来的对象,然后由service将取出的数据做进一步的处理反馈给前台用户。
4.2 右连接
public List<Object> leftJoin(String staffName) {
Session session=sessionFactory.getCurrentSession();
try{
Transaction tx=session.beginTransaction();
String hql="from Staff staff Right JOIN staff.department where staff.employeeName='"+staffName+"'"+staffName+"'";
List<Object> list=session.createQuery(hql).list();
tx.commit();
}catch(Exception e){
e.printStackTrace();
session.close();
}
同样需要注意hql语句的书写:Stringhql="from Staff staff Right JOIN staff.department where staff.employeeName='"+staffName+"'";中staff.department对应配置文件里面name属性值相同。
查找结果如下:
4.3 交叉连接
public List<Object> leftJoin(String staffName) {
Session session=sessionFactory.getCurrentSession();
try{
Transaction tx=session.beginTransaction();
String hql="from Staff staff,Department department where staff.departId=department.departmentId and staff.employeeName='"+staffName+"'"+staffName+"'";
List<Object> list=session.createQuery(hql).list();
tx.commit();
}catch(Exception e){
e.printStackTrace();
session.close();
如上代码所示的查询方式不需要我们在Model层做任何配置(与左右连接查找的不同),依然能得到我们想要的结果,可能你会觉得很棒,因为不需要进行繁琐的配置,也不会在数据库中生成额外的外键,但上述语句翻译为sql用的是交叉连接,这种方式一旦表非常大的时候搜索效率非常低下。
5.左、右连接查询的区别
通过上面演示的例子,我们很难明白左右连接的差别在什么地方。其实左右连接的差异可以理解为,左连接以左表的数据为准,向右查找其他配置的表;右连接以右表的数据为准,向左查找其他配置的表。举个例子:假设我们有如下三张表,Student、Score、Classes,即学生、成绩、班级表,以Student-Score-Classes的连接顺序演示左右连接的差异。表中数据如下:
左连接查找即以Student表为基准,hql=from Student stu LEFT JOIN stu.score LEFT JOIN stu.clas,通过查找满足条件的Student表的行,依次在Score、Classes表中查找,由于Student表中有三行数据,那么左连接查找返回的值包括三个Object数组,如果连接的表没有与左表匹配的行,以null补充。其返回结果如下:
右连接查找即以Classes表为基准,hql= from Student stu RIGHT JOIN stu.score RIGHT JOIN stu.clas,通过查找满足条件的Classes表的行,依次在Score、Student表中查找,由于Classes表中有三行数据,那么左连接查找返回的值包括一个Object数组,其返回结果如下:
*补充. SessionFactory获取Session的两种方式
①sessionFactory.openSession()
创建一个新的session对象,而且每次使用都是创建一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session。
②sessionFactory.getCurrentSession()
获取当前上下文一个session对象,当第一次使用此方法时,会自动产生一个session对象,并且连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一,简单而言,getCurrentSession 就是:如果有已经使用的,用旧的,如果没有,建新的。
注意 :在实际开发中,往往使用getCurrentSession多,因为一般是处理同一个事务(即使用一个数据库),所以在一般情况下比较少使用openSession,要使用sessionFactory.getCurrentSession(),需要对hibernate.xml文件进行配置,在配置文件中添加如下内容:
<span style="font-size:12px;"><property name="hibernate.current_session_context_class">thread </property> </span>