前年给地图技术审查中心做了一个培训的报名系统,功能需求比较简单,由于当时刚开始摸索java就只能照葫芦画瓢的使用JDBC写的程序。这是中百信公司的遗留项目,我接手过来的,仿照以前的代码写得。
出现问题的代码:
<div id="content">
<div class="locbackground">
</div>
<div class="text">
<center>
<h1>
查看培训(会议)报名信息
</h1>
<div><input type="button" value="导出会议(培训)报名信息 " οnclick="location.href='/dtsc/pxbm/outRegisterByConference.jsp?cid=<%=request.getParameter("cid")%>'"/></div>
<br/><table class="listCases" width="100%" border="0"
style="width: 100%; FONT-SIZE: 18px; word-break: break-all"
cellspacing="1" cellpadding="5" bgcolor=#455ca2>
<thead>
<tr height="40px">
<th width="70" bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
操作
</th>
<th width="30" bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
序号
</th>
<th width="30" bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
姓名
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
性别
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
民族
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
身份证号
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
工作单位
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
职务(职称)
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
手机号码
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
乘坐何种 交通工具(班次)
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
到达时间
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
注册时间
</th>
<th bgcolor=#dcdcdc align="center" class=""
style="font-size: 14px; FONT-WEIGHT: bold">
ip地址
</th>
</tr>
</thead>
<%
Collection registerId = conferenceRegisterAssignOp.getRegisterIdByConferenceId(Integer.parseInt(request.getParameter("cid")));
Iterator it = registerId.iterator();
int index = 1;
while (it.hasNext()) {
Integer integer = (Integer)it.next();
int rid = integer.intValue();
Register temp = registerOp.getCaseInfo(rid);
%>
<tr>
<td class="listContent">
<a href="dtsc/pxbm/editRegister.jsp?registerId=<%=temp.getId()%>">编辑</a>
<br />
<br />
<a href="dtsc/pxbm/deleteRegister.jsp?registerId=<%=temp.getId()%>">删除</a>
<br />
<br />
<a href="dtsc/pxbm/editRegister.jsp?registerId=<%=temp.getId()%>">查看详细</a>
</td>
<td class="listContent"><%=index%></td>
<td class="listContent"><%=temp.getName() %></td>
<td class="listContent"><%=CodeSet.getSex(temp.getSex())%></td>
<td class="listContent"><%=temp.getRace()%></td>
<td class="listContent"><%=temp.getIdentificationId() %></td>
<td class="listContent"><%=temp.getDepartment()%></td>
<td class="listContent"><%=temp.getPositionOrIdentity()%></td>
<td class="listContent"><%=temp.getMobilephone()%></td>
<td class="listContent"><%=temp.getDeparture()%></td>
<td class="listContent"><%=temp.getArrivingTime()%></td>
<td class="listContent"><%=temp.getRegisterTime()%></td>
<td class="listContent"><%=temp.getIp()%></td>
</tr>
<%
++index;
}
%>
</table>
</center>
</div>
</div>
因为是嵌在JSP页面的中代码,在java代码后面跟的是一些显示用的HTML代码。
注意这一段代码:
Collection registerId = conferenceRegisterAssignOp.getRegisterIdByConferenceId(Integer.parseInt(request.getParameter("cid")));
Iterator it = registerId.iterator();
int index = 1;
while (it.hasNext()) {
Integer integer = (Integer)it.next();
int rid = integer.intValue();
Register temp = registerOp.getCaseInfo(rid);
这里边先根据cid(培训会议表id)取到了参加本次会议的注册人员的id列表。
Collection registerId = conferenceRegisterAssignOp.getRegisterIdByConferenceId(Integer.parseInt(request.getParameter("cid")));
然后再遍历这个列表,对每一个注册人员id,都取出这个人员的详细信息。
Register temp = registerOp.getCaseInfo(rid);
这样在报名的数量达到200条的时候运行起来的时间大约为40s到70秒s。由于这个页面的table中的行tr是在后台逐条生成的,再Collection遍历是陆陆续续发送到浏览器的,这样会使浏览器等待页面的时间太长,导致浏览器与后台Web Server的连接超过TimeOut时长,断开连接。反应到前端浏览器的现象就是页面的前半部分加载完成,列表没有全部加载出来。改进的代码:
原因分析清楚之后,我们需要改进这个查找机制,需要把这两次操作合并到一次SQL查询中完成,让SQL在后台一次就把我们需要的注册人员的详细信息查询出来。
Collection registers = conferenceRegisterAssignOp.getRegistersByConferenceId(Integer.parseInt(request.getParameter("cid"))); Iterator it = registers.iterator(); int index = 1; while (it.hasNext()) { Register temp = (Register)it.next();
在这里,我只用了一次查询:getRegistersByConferenceId就取出来了所有的注册信息。这个函数是这样写的:
//根据会议Id获得参加会议的报名情况 public Collection<Register> getRegistersByConferenceId(int conferenceId) throws Exception { Statement stmt=con.createStatement(); ResultSet rst=stmt.executeQuery("SELECT dtsc_register.id, dtsc_register.name, dtsc_register.sex, dtsc_register.age, dtsc_register.race,"+ "dtsc_register.identificationId, dtsc_register.department, dtsc_register.positionOrIdentity, dtsc_register.mobilephone,"+ "dtsc_register.departure, dtsc_register.arrivingTime, dtsc_register.ip, dtsc_register.registerTime, dtsc_register.education,"+ "dtsc_register.address, dtsc_register.zipcode, dtsc_register.suozaibumen, dtsc_register.telephone, dtsc_register.isFirst "+ "FROM dtsc_conferenceRegisterAssign INNER JOIN "+ "dtsc_register ON dtsc_conferenceRegisterAssign.registerId = dtsc_register.id "+ "WHERE dtsc_conferenceRegisterAssign.conferenceId = "+conferenceId+" ORDER BY dtsc_conferenceRegisterAssign.id"); Collection<Register> registers = new ArrayList<Register>(); while (rst.next()) { Register register=new Register(); register.setId(rst.getInt("id")); register.setName(rst.getString("name")); register.setSex(rst.getInt("sex")); register.setRace(rst.getString("race")); register.setIdentificationId(rst.getString("identificationId")); register.setDepartment(rst.getString("department")); register.setPositionOrIdentity(rst.getString("positionOrIdentity")); register.setMobilephone(rst.getString("mobilephone")); register.setDeparture(rst.getString("departure")); register.setArrivingTime(rst.getString("arrivingTime")); register.setIp(rst.getString("ip")); register.setRegisterTime(rst.getString("registerTime")); register.setEducation(rst.getString("education")); register.setAddress(rst.getString("address")); register.setZipcode(rst.getString("zipcode")); register.setSuozaibumen(rst.getString("suozaibumen")); register.setTelephone(rst.getString("telephone")); register.setIsFirst(rst.getInt("isFirst")); registers.add(register); } con.close(); return registers; }
通过INNER JOIN就可以通过一次数据库的查询达到目的。结论:
对比前后两种代码,我们看到,对数据库的操作次数越少越好。如前面我们总共进行了<本次会议报名人数+1>次数据库查询,后着我们只进行了一次Inner Join查询操作。差距显而易见。所以在表之间靠外键进行联系时,如果你用原始的JDBC语句,请一次完成查询。
如果你使用的是HIbernate这样的ORM框架,那么恭喜你,你不用为构造复杂的SQL而操心,她内部的多层缓存机制和Lazy懒惰机制会使你最少的进行数据库查询(当然你需要了解更多的配置才行),大大提高效率。