我们集团多年前上了一套OA系统,jsp + javabean + servlet,没有使用任何框架,model1。
数据库:SqlServer 2000
web服务器:Resin 2.1.6
开发者是合肥某家专业OA公司,应该是为我们定制的。具体情况我当时没有入职,不清楚。
从我第一天使用它就感觉很慢。近日发现经常死机,一天需要多次重启服务。2G内存,4CPU的服务器,经常cpu100%,全被sqlserver占用,db连动数动辄上千。
观察了一天,得出结论:要想彻底解决,只有辛苦一番了。
此次修改不涉及业务逻辑部分。
动手修改之后怒火却逐渐上升,好在凭借几十年的修身养性平息下来了,不过一天下来却得感冒,不知道是否跟这个有关。
笔录一些东西,感慨一番。或供大家批判、或引以为鉴。当年写程序的那个小伙子,如果你能看到,不知道有没有什么感慨呢?
(1)死机最主要原因出在数据库连接的管理上。
数据库连接类(DBConnectionManager.java)。
数据库操作类(DBQuery.java),在构造函数中取得DBConnectionManager的一个单例。
该类特点是在方法executeQuery、executeUpdate之中,每次都从连接池中申请一个连接。
DBQuery通过java Bean使用,而在绝大部分jsp页面都包含:
<jsp:useBean id= "dbquery " class= "front.DBQuery " scope= "page "/>
也就是说打开一个页面,就产生一个Connection,观察到的sqlserver连接峰值3200+ ,即使是ORACLE,也很夸张。
至于为什么这样,参考(2)。
另外,还有一个函数返回值是ResultSet,但是在函数最后调用了freeConnection(),经常抛出“连接已关闭”错误也就不奇怪了。
(2)JSP页面中直接调用dbquery执行SQL查询。除少数正常关闭外,大部分ResultSet只管打开,不管关闭。正所谓:只管杀来不管埋!有魄力!
另外还有一部分是这样写的,我算他关闭了一半-_-!:
ResultSet myrs2=dbquery.executeQuery( "xxxxxx ");
if(myrs2.next()){
myrs2.close();
}
有个地方还加了一个判断:
i = 0;
while(rs.next()){
i ++;
}
if(i > 0)
rs.close();
这种……。
另附一个超强文件,文件名:whcqd_cc.jsp (22k),只要一编辑,eclipse立即停止响应,cup 100%,无法解析文档结构图。只好结束进程,转到ultraedit中修改。
这个文件一部分代码如下:
zuzhirs1 = dbquery.executeQuery( "…… ");
//查找一级组织
while(zuzhrs1.next()){
zuzhirs2 = dbquery.executeQuery( "…… ");
//查找二级组织
while(zuzhirs2.next()){
……
//查找七级组织
zuzhirs7 = dbquery.executeQuery( "…… ");
while(zuzhirs7.next()){
……
}
zuzhirs7.close(); //太震撼了,居然关闭了第七个rs
}
}
7个zuzhirs中,关闭1/7。
(3)sql语句的优化,很少使用关联查询,最常见的是,需要用到时,随时打开一个游标查询(请考虑第一条、第二条),例如:
rs1 = dbquery.executeQuery( "取用户信息 ");
while(rs1.next()){
String yhh = rs1.getString( "yhh "); //用户号
String yhmc;
rstmp = dbquery.executeQuery( "select 名称 from xxx where yhh = ' " + yhh + " ' ";
if(rstmp.next()){
yhmc = rstmp.getString( "名称 ");
}
……
//下一个类似的循环
}
某个大小45k的文件,名称:W_userdef_sqmodi.jsp,改完后我直接昏倒,清醒后不忘作了一个统计:
count(ResultSet) == 34
count(while) == 16
(4)超强的分页算法。
rs=dbquery.executeQuery( "select xxx, xxx from tablexxx order by mail_date desc ");
i = (intPage-1) * intPageSize;