前年给地图技术审查中心做了一个培训的报名系统,功能需求比较简单,由于当时刚开始摸索java就只能照葫芦画瓢的使用JDBC写的程序。这是中百信公司的遗留项目,我接手过来的,仿照以前的代码写得。
出现问题的代码:
<div id="content"> <div class="locbackground"> </div> <div class="text"> <center> <h1> 查看培训(会议)报名信息 </h1> <div><input type="button" value="导出会议(培训)报名信息 " onclick="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);
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懒惰机制会使你最少的进行数据库查询(当然你需要了解更多的配置才行),大大提高效率。