TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
堵塞连接泄漏
看看下面的代码:
Datasource source=...
Connection conn=source.getConnection();
Statement stat=conn.createStatement();
String command="insert into User values("root","123456");
stat.executeUpdate(command);
conn.close();
上面代码看上去很整洁:我们打开一个连接,发送命令,并立即关闭连接。但是,这里有一个致命的错误。如果某一方法调用抛出一个异常,则永远无法调用close()方法!在这里,生气的用户可能会多次重新提交请求,每次单击都会泄漏一个连接对象。要解决这个问题,就要在finally块中放置close()调用:
Datasource source=...
Connection conn=source.getConnection();
try{
Statement stat=conn.createStatement();
String command="insert into User values("root","123456");
stat.executeUpdate(command);
}
finally{
conn.close();
}
这个简单的规则完全可以解决连接泄漏的问题,但它没有处理异常,如果象下面那样:
Datasource source=...
Connection conn=null;
try{
conn=source.getConnection();
Statement stat=conn.createStatement();
String command="insert into User values("root","123456");
stat.executeUpdate(command);
}
catch(SQLExceptin e){
//日志记录
}
finally{
conn.close();
}
代码中又有两个小错误。首先,如果调用getConnection会抛出一个异常,而conn仍然是null,这时将不能调用close()。此外,调用close()也会抛出SQLException。正确的代码应该为:
Datasource source=...
try{
Connection conn=source.getConnection();
try{
Statement stat=conn.createStatement();
String command="insert into User values("root","123456");
stat.executeUpdate(command);
}
finally{
conn.close();
}
}
catch(SQLException e){
//日志记录
}
内部的try语句块确保连接被关闭,外部的try语句块确保异常被记录。
当然,还可以使用throws SQLException来标注方法并将外部try语句块留给调用者处理。如:
boolean loggedIN;
public void doLogin() throws SQLException, NamingException {
Context ctx = new InitialContext();
if (ctx == null) throw new NamingException("No initial context");
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
if (ds == null) throw new NamingException("No data source");
Connection conn = ds.getConnection();
if (conn == null) throw new SQLException("No connection");
try {
PreparedStatement passwordQuery = conn.prepareStatement(
"SELECT password from Users WHERE username = ?");
passwordQuery.setString(1, name);
ResultSet result = passwordQuery.executeQuery();
if (!result.next()) return;
String storedPassword = result.getString("password");
loggedIn = password.equals(storedPassword.trim());
}
finally {
conn.close();
}
}
这是调用这个方法的代码:
public String login() {
try {
doLogin();
}
catch (SQLException ex) {
logger.log(Level.SEVERE, "loginAction", ex);
return "internalError";
}
catch (NamingException ex) {
logger.log(Level.SEVERE, "loginAction", ex);
return "internalError";
}
if (loggedIn)
return "loginSuccess";
else
return "loginFailure";
} |
|