基于SSH的JavaEE开发中采用HQL进行多表查询的几种方法解析

本文所述的多表查询仅在各个表无外键等约束关系下的查询,不涉及join fetch,这里提供以下三种方法进行SSH中的多表查询:

1 采用SQL语句,将结果保存至List中,利用列表下标进行显示

2 采用HQL语句,将查询结果拆分成ORM后的各个对象进行显示

3 采用HQL语句,用HashMap接收查询结果

数据库表结构

在本例中,我们新建两张数据表,其中表的结果如下所示:

–创建学生表

create table stu3401(

id bigint primary key identity(1,1),

name varchar(50) not null,

password varchar(50) not null

);

–创建学生详细信息表

create table stuDetail(

id int primary key identity(1,1),

stuId bigint,

address varchar(100),

school varchar(50),

)

SQL脚本如下:

–在表stu3401中插入10条数据

insert into stu3401 values(‘a’,3401);

insert into stu3401 values(‘b’,3401);

insert into stu3401 values(‘c’,3401);

insert into stu3401 values(‘d’,3401);

insert into stu3401 values(‘e’,3401);

insert into stu3401 values(‘f’,3401);

insert into stu3401 values(‘g’,3401);

insert into stu3401 values(‘h’,3401);

insert into stu3401 values(‘i’,3401);

insert into stu3401 values(‘j’,3401);

–在表stuDetail中插入10条数据

insert into stuDetail values(1,’桂林市金鸡路1号’,'桂林电子科技大学a校区’);

insert into stuDetail values(2,’桂林市金鸡路2号’,'桂林电子科技大学b校区’);

insert into stuDetail values(3,’桂林市金鸡路3号’,'桂林电子科技大学c校区’);

insert into stuDetail values(4,’桂林市金鸡路4号’,'桂林电子科技大学d校区’);

insert into stuDetail values(5,’桂林市金鸡路5号’,'桂林电子科技大学e校区’);

insert into stuDetail values(6,’桂林市金鸡路6号’,'桂林电子科技大学f校区’);

insert into stuDetail values(7,’桂林市金鸡路7号’,'桂林电子科技大学g校区’);

insert into stuDetail values(8,’桂林市金鸡路8号’,'桂林电子科技大学h校区’);

insert into stuDetail values(9,’桂林市金鸡路9号’,'桂林电子科技大学i校区’);

insert into stuDetail values(10,’桂林市金鸡路10号’,'桂林电子科技大学j校区’);

1 采用SQL语句,将结果保存至List中,利用列表下标进行显示

1.1 概况

这种方法采用SQL语句,未将数据表的关系(R)进行对象(O)映射(M),因此,我们在此将查询得到的数据用ArrayList进行接收,并在前台用列表的下标进行显示,具体操作如下:

1.2 DAO层

首先我们采用SQL语句进行查询,其中DAO中代码如下:

/*

* 使用SQL语言对数据库进行查询,将结果返回至一个列表中

* */

public List queryBySQL(String queryString)

{

log.debug(“query data using function createSQLQuery and return a list”);

try {

return this.getSession().createSQLQuery(queryString).list();

} catch (RuntimeException re) {

// TODO: handle exception

log.error(“query error”,re);

throw re;

}

}

1.3 业务层

Action中的代码如下:

public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) {

String queryString=”select * from stu3401 s,stuDetail t where s.id=t.stuId”;

List stuList = stu3401Service.queryBySQL(queryString);

request.setAttribute(“result”, stuList);

return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[[1, a, 3401, 1, 1, 桂林市金鸡路1号, 桂林电子科技大学a校区],

[2, b, 3401, 2, 2, 桂林市金鸡路2号, 桂林电子科技大学b校区],

[3, c, 3401, 3, 3, 桂林市金鸡路3号, 桂林电子科技大学c校区]

[4, d, 3401, 4, 4, 桂林市金鸡路4号, 桂林电子科技大学d校区],

[5, e, 3401, 5, 5, 桂林市金鸡路5号, 桂林电子科技大学e校区],

[6, f, 3401, 6, 6, 桂林市金鸡路6号, 桂林电子科技大学f校区],

[7, g, 3401, 7, 7, 桂林市金鸡路7号, 桂林电子科技大学g校区],

[8, h, 3401, 8, 8, 桂林市金鸡路8号, 桂林电子科技大学h校区],

[9, i, 3401, 9, 9, 桂林市金鸡路9号, 桂林电子科技大学i校区],

[10, j, 3401, 10, 10, 桂林市金鸡路10号, 桂林电子科技大学j校区],null]

它是一个长度为11的数组列表obj1[11](ArrayList,使用数组实现List数据结构,实质上就是一个长度可变的数组):该列表可描述为Object[11] obj1 = {obj10[7],obj11[7],…obj19[7],null}(注意最后还有一个null,但是其size为10,modCount也为 10),其中的每一个元素是一个长度为7的Object类型的对象列表(数组),这里表示为obj1j[7],(j=0,1,…9)。我们以j = 0为例,对于对象列表obj10[7],它包含7个属性,分别对应两张数据表中的7个字段,其中的每个字段都被强制类型转换成Object类型(因为 Object类是所有类的父类,)。因此,stuList就可理解为一个对象列表(数组)的列表(数组)。

1.4 表示层

前台JSP页面代码如下:

<table width=”600px” align=”center”>

<thead>

<tr>

<td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

</tr>

</thead>

<tbody>

<c:if test=”${!empty result}”>

<c:forEach items=”${result}” var=”Item”>

<tr>

<td>${Item[1]}</td>

<td>${Item[5]}</td>

<td>${Item[6]}</td>

</tr>

</c:forEach>

</c:if>

<c:if test=”${empty result}”>

<tr>

<td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

onmouseover=”this.bgColor = ‘#DEE7FF’;”

onmouseout=”this.bgColor=’#EFF3F7′;”>

没有找到相应的记录

</td>

</tr>

</c:if>

</tbody>

</table>

1.5 小结

这种方法的弊端在于当我们对数据库进行维护时,若需要更改(如添加或删除)某些字段,则在前台JSP页面中,我们还需要对其下标进行修改,一方面给开发维护带来很大不便,另一方面也容易出错。

2采用HQL语句,将查询结果拆分成ORM后的各个对象进行显示

2.1 概况

与方法一不同,这种方法对数据表的关系进行了ORM映射,也就是我们可以对查询的结果进行对象的操作。在本例中,因为涉及到两张表的查询,因此我们需要对查询结果进行分拆后再强制类型转换,具体实现如下:

2.2 DAO层

以下是DAO层的代码:

/*

* 使用SQL语言对数据库进行查询,将结果返回至一个列表中

* */

public List queryByHql(String queryString)

{

log.debug(“query data from two tables and show data using hql object”);

try {

return getHibernateTemplate().find(queryString);

} catch (RuntimeException re) {

// TODO: handle exception

log.error(“query error”,re);

throw re;

}

}

2.3 业务逻辑层

Action中的代码如下:

public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) {

String queryString=”from Stu3401 s,StuDetail t where s.id=t.stuId”;

List stuList = stu3401Service.queryByHql(queryString);

List<Stu3401> stuList1=new ArrayList<Stu3401>();

List<StuDetail> stuList2=new ArrayList<StuDetail>();

Object[] obj = null;

for(int i=0;i<stuList.size();i++)

{

obj = (Object[])stuList.get(i);

stuList1.add((Stu3401)obj[0]);

stuList2.add((StuDetail)obj[1]);

}

request.setAttribute(“result1″, stuList1);//保存表1数据

request.setAttribute(“result2″, stuList2);//保存表2数据

return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[[com.lyw.loginCoridc.model.domain.Stu3401@130c35c, com.lyw.loginCoridc.model.domain.StuDetail@db8522], [com.lyw.loginCoridc.model.domain.Stu3401@19a64, com.lyw.loginCoridc.model.domain.StuDetail@13f54ae],

……

……

[com.lyw.loginCoridc.model.domain.Stu3401@5b77c, com.lyw.loginCoridc.model.domain.StuDetail@151685f], null]

它也是一个长度为11的数组列表,假设定义为obj1[11] = {obj10[2],obj11[2],…,obj19[2],null},其中的每一个元素是一个长度为2的Ojbect类型的对象列表(数组),这里表示为obj1j[2],(j=0,1,…9)。我们以j = 0为例,对于对象列表obj10[2],其第一个元素是第一张数据表所映射的Stu3401类型的对象,包括id,name和password三个属性;第二个元素是第二张数据表所映射的StuDetail类型的对象,包括id,address,school和stuId四个属性。因此我们可以通过对象对查询进过进行保存,代码如上。

2.4 表示层

前台JSP页面代码如下:

<table width=”600px” align=”center”>

<thead>

<tr>

<td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

</tr>

</thead>

<tbody>

<c:if test=”${!(empty result1 || empty result2)}”>

<c:forEach items=”${result1}” var=”Item1″ varStatus=”s”>

<c:forEach items=”${result2}” var=”Item2″ begin=”${s.index}” step=”${fn:length(result1)-s.index}”>

<tr>

<td>${Item1.name}</td>

<td>${Item2.address}</td>

<td>${Item2.school}</td>

</tr>

</c:forEach>

</c:forEach>

</c:if>

<c:if test=”${empty result1 || empty result2}”>

<tr>

<td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

onmouseover=”this.bgColor = ‘#DEE7FF’;”

onmouseout=”this.bgColor=’#EFF3F7′;”>

没有找到相应的记录

</td>

</tr>

</c:if>

</tbody>

</table>

在上面代码中,为了求得列表的长度,我们引入了标签fn,因此还需在页面上导入JSTL标签库:

<%@ taglib prefix=”fn” uri=”http://java.sun.com/jsp/jstl/functions” %>

关于fn标签函数的函数说明可参见:http://www.coridc.com/archives/2349.html

2.5 小结

这种方法相对第一种方法来讲,最大的好处就是能够通过对象的属性进行显示,而不再担心下标的问题。但该方法也存在一个问题,当查询所涉及到N张表时,我们就需要向前台传入N个参数,而且在前台的Foreach循环控制上,会显得很麻烦。

3 采用HQL语句,用HashMap接收查询结果

3.1 概况

在方法二中,我们从后台传递N(N表示数据查询所涉及到的表的数量)个列表至前台,由此带来的不便在2.5节中已略有阐述。在方法三中,我们将采用HashMap来接收查询结果并传递到前台,详细操作如下:

3.2 DAO层

因为方法三与方法二都采用HQL语句查询,因此方法三的DAO层代码与方法二相同。

3.3 业务逻辑层

Action中的代码如下:

public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

HttpServletRequest request, HttpServletResponse response) {

 

String queryString1=”select new map(s.name as name,t.address as address,t.school as school) from Stu3401 s,StuDetail t where s.id=t.stuId”;

List stuList = stu3401Service.queryByHql(queryString1);

request.setAttribute(“result”, stuList);

return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[{address=桂林市金鸡路1号, school=桂林电子科技大学a校区, name=a},

{address=桂林市金鸡路2号, school=桂林电子科技大学b校区, name=b},

{address=桂林市金鸡路3号, school=桂林电子科技大学c校区, name=c},

{address=桂林市金鸡路4号, school=桂林电子科技大学d校区, name=d},

{address=桂林市金鸡路5号, school=桂林电子科技大学e校区, name=e},

{address=桂林市金鸡路6号, school=桂林电子科技大学f校区, name=f},

{address=桂林市金鸡路7号, school=桂林电子科技大学g校区, name=g},

{address=桂林市金鸡路8号, school=桂林电子科技大学h校区, name=h},

{address=桂林市金鸡路9号, school=桂林电子科技大学i校区, name=i},

{address=桂林市金鸡路10号, school=桂林电子科技大学j校区, name=j}]

它是一个长度为10的数组列表,列表的每一个元素都是一个HashMap<K,V>,如stuList[0] = {address=桂林市金鸡路1号, school=桂林电子科技大学a校区, name=a},那么我们可以在JSP页面直接通过HashMap的Key来取得相对应的Value,前台代码见3.4节。

3.4 表示层

前台JSP页面代码如下:

<table width=”600px” align=”center”>

<thead>

<tr>

<td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

</tr>

</thead>

<tbody>

<c:if test=”${!empty result}”>

<c:forEach items=”${result}” var=”Item”>

<tr>

<td>${Item.name}</td>

<td>${Item.address}</td>

<td>${Item.school}</td>

</tr>

</c:forEach>

</c:if>

<c:if test=”${empty result}”>

<tr>

<td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

onmouseover=”this.bgColor = ‘#DEE7FF’;”

onmouseout=”this.bgColor=’#EFF3F7′;”>

没有找到相应的记录

</td>

</tr>

</c:if>

</tbody>

</table>

3.5 小结

很明显,这种方法比第一种和第二种方法要简便的多,而且易于维护,代码量小,剩下的,你们懂的。

http://www.coridc.com/archives/2350.html

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓