最近做一个统计数据的小工具,发现在自己机器上运行正常,移到其他机器上就报:
java.sql.SQLException: 关闭的连接
的错误,开始以为是防火墙的问题,经过测试,发现和防火墙无关。
原来还是程序写得有问题,在获得数据库连接时,若重复使用Connection变量,则除了判断为空外,还要判断是否关闭,见下面代码黑体字部分。
/**
* 获得数据库连接
* @return
*/
public Connection getConnection(){
try {
//判断有问题
//if(conn != null)
//应该判断连接是否已关闭
if(conn != null && !conn.isClosed())
return conn;
String dbDriver = DBDRIVER;
String dbUrl = DBURL;
String dbUser = DBUSER;
String dbPwd = DBPWD;
Class.forName(dbDriver).newInstance();
conn = DriverManager.getConnection(dbUrl, dbUser, dbPwd);
if(conn == null)
throw new Exception("获取数据库连接失败!");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
否则有可能Connection 变量不为空(null),但出现连接已关闭的问题。
查询数据表处理见下面的函数:
public void statOne(CaclCell cc) {
try {
getConnection();
Statement st = conn.createStatement();
String statYear = cc.getStatYear();
String lastStatYear = cc.getLastStatYear();
String startDate = cc.getStartDate();
String endDate = cc.getEndDate();
String sql = cc.getSql();
if(sql != null && !"".equals(sql.trim())){
String sql2 = sql.replace("[startDate]", startDate);
sql2 = sql2.replace("[endDate]", endDate);
sql2 = sql2.replace("[statYear]", statYear);
sql2 = sql2.replace("[lastStatYear]", lastStatYear);
log.info("sql=" + sql2);
ResultSet rs=st.executeQuery(sql2);
rs.next();
String result = rs.getString(1);
cc.setResult(result);
hmOutput.put(cc.getDataCell(), cc);
} conn.close();
} catch (Exception e) {
log.error("statOne failed.", e);
try {
if(conn != null)
conn.close();
} catch (Exception e2) {
log.error("close database connection failed.", e2);
}
}finally{
try {
if(conn != null)
conn.close();
} catch (Exception e2) {
log.error("close database connection failed.", e2);
}
}
}
但若将代码做一些调整,错误又不出现了。
/**
* 单子段统计
*
*/
public void statOne(CaclCell cc) {
try {
String statYear = cc.getStatYear();
String lastStatYear = cc.getLastStatYear();
String startDate = cc.getStartDate();
String endDate = cc.getEndDate();
String sql = cc.getSql();
if(sql != null && !"".equals(sql.trim())){
String sql2 = sql.replace("[startDate]", startDate);
sql2 = sql2.replace("[endDate]", endDate);
sql2 = sql2.replace("[statYear]", statYear);
sql2 = sql2.replace("[lastStatYear]", lastStatYear);
log.info("sql=" + sql2);
getConnection();
Statement st = conn.createStatement();
ResultSet rs=st.executeQuery(sql2);
rs.next();
String result = rs.getString(1);
cc.setResult(result);
hmOutput.put(cc.getDataCell(), cc);
conn.close();
}
} catch (Exception e) {
log.error("statOne failed.", e);
try {
if(conn != null)
conn.close();
} catch (Exception e2) {
log.error("close database connection failed.", e2);
}
}
}
也就是getConnection()紧挨executeQuery() 语句。
原因是什么呢,其实和黑体代码位置没有关系。而是如果放在if语句中,则只需要一个连接(只有一条满足要处理条件),而如果statOne()调用两次,则出现了同样的问题。
说明什么呢:conn.close(); 数据库连接关闭后,conn并不会为空。
所以要使用conn.isClosed()来判断数据库连接是否已关闭,如关闭则重新建立连接,如没关闭则继续使用;
黑体字没有正常显示,见<strong></strong>包含部分
补充说明:
连接建立需要较长时间,我的双CPU性能很好的机器要5秒左右,如果每次处理都关闭后再连接,系统运行势必会非常的慢。可以在处理完所有的数据后再关闭数据库连接,这样就能获得较高的处理性能。