JSP 实现删除数据库连接的详细方法
在 JSP 应用程序中,管理数据库连接是确保资源有效利用和系统稳定性的关键,不当的连接管理可能导致资源泄漏、性能下降甚至应用程序崩溃,本文将详细介绍如何在 JSP 中实现删除(关闭)数据库连接,涵盖多种场景和技术,并提供最佳实践建议。
理解数据库连接的重要性
在 Web 应用程序中,数据库连接通常涉及以下步骤:
- 加载数据库驱动:使用
Class.forName()方法加载相应的 JDBC 驱动。 - 建立连接:通过
DriverManager.getConnection()或数据源获取连接对象。 - 创建语句:使用连接对象创建
Statement或PreparedStatement。 - 执行 SQL:执行查询或更新操作。
- 处理结果:处理
ResultSet(如果有)。 - 关闭资源:按照相反顺序关闭
ResultSet、Statement和Connection。
未正确关闭连接会导致连接池耗尽,影响应用程序的可用性,确保在不再需要时及时关闭连接至关重要。
基本关闭连接的方法
使用 finally 块确保关闭
无论操作是否成功,都应确保连接被关闭,使用 try-catch-finally 结构是常见的做法。
<%@ page import="java.sql." %>
<%
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
// 创建语句
stmt = conn.createStatement();
// 执行查询
rs = stmt.executeQuery("SELECT FROM users");
// 处理结果
while(rs.next()) {
out.println("User: " + rs.getString("username"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
// 关闭结果集
if(rs != null) {
try { rs.close(); } catch(SQLException e) { e.printStackTrace(); }
}
// 关闭语句
if(stmt != null) {
try { stmt.close(); } catch(SQLException e) { e.printStackTrace(); }
}
// 关闭连接
if(conn != null) {
try { conn.close(); } catch(SQLException e) { e.printStackTrace(); }
}
}
%>
使用 JDBC 的 try-with-resources(推荐)
自 Java 7 起,可以使用 try-with-resources 语法自动管理资源关闭,代码更简洁且安全。

<%@ page import="java.sql." %>
<%
String url = "jdbc:mysql://localhost:3306/mydb";
String user = "user";
String password = "password";
String query = "SELECT FROM users";
try {
Class.forName("com.mysql.cj.jdbc.Driver");
try (
Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
) {
while(rs.next()) {
out.println("User: " + rs.getString("username"));
}
}
} catch(Exception e) {
e.printStackTrace();
}
%>
优点:
- 自动关闭实现了
AutoCloseable接口的资源。 - 代码更简洁,减少出错可能。
在 JSP 中使用连接池管理连接
直接在 JSP 中管理数据库连接并非最佳实践,推荐使用连接池(如 DBCP、C3P0 或服务器自带的连接池)来优化连接管理,以下是使用连接池的步骤:
配置数据源(以 Apache DBCP 为例)
在 WEB-INF/lib 目录下添加所需的 JAR 文件,如 commons-dbcp2.jar 和 mysql-connector-java.jar。
在 context.xml 中配置数据源:
<Resource name="jdbc/mydb" auth="Container"
type="javax.sql.DataSource" username="user" password="password"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb"
maxActive="20" maxIdle="10" maxWait="-1"/>
在 JSP 中获取并关闭连接
<%@ page import="javax.naming., javax.sql., java.sql." %>
<%
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 通过 JNDI 获取数据源
Context initCtx = new InitialContext();
DataSource ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/mydb");
conn = ds.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT FROM users");
while(rs.next()) {
out.println("User: " + rs.getString("username"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
// 关闭结果集和语句
if(rs != null) {
try { rs.close(); } catch(SQLException e) { e.printStackTrace(); }
}
if(stmt != null) {
try { stmt.close(); } catch(SQLException e) { e.printStackTrace(); }
}
// 归还连接给连接池
if(conn != null) {
try { conn.close(); } catch(SQLException e) { e.printStackTrace(); }
}
}
%>
注意: 使用连接池时,conn.close() 实际上是将连接归还给池,而不是物理关闭连接。

使用 MVC 模式优化连接管理
在 JSP 中直接编写数据库操作代码不利于维护和扩展,推荐采用 MVC(Model-View-Controller)模式,将业务逻辑与视图分离。
创建 DAO(Data Access Object)类
// UserDao.java
package com.example.dao;
import java.sql.;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
public class UserDao {
private DataSource dataSource;
public UserDao(DataSource dataSource) {
this.dataSource = dataSource;
}
public List<String> getUsernames() throws SQLException {
List<String> usernames = new ArrayList<>();
String query = "SELECT username FROM users";
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery()) {
while(rs.next()) {
usernames.add(rs.getString("username"));
}
}
return usernames;
}
}
创建 Servlet 作为控制器
// UserServlet.java
package com.example.servlet;
import com.example.dao.UserDao;
import javax.servlet.;
import javax.servlet.http.;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.List;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class UserServlet extends HttpServlet {
private UserDao userDao;
@Override
public void init() throws ServletException {
try {
Context initCtx = new InitialContext();
DataSource ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/mydb");
userDao = new UserDao(ds);
} catch(Exception e) {
throw new ServletException("Cannot initialize DataSource", e);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<String> usernames = userDao.getUsernames();
request.setAttribute("usernames", usernames);
RequestDispatcher dispatcher = request.getRequestDispatcher("/users.jsp");
dispatcher.forward(request, response);
} catch(SQLException e) {
throw new ServletException("Database error", e);
}
}
}
创建 JSP 视图
<!-users.jsp -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head><title>Users</title></head>
<body>
<h2>User List</h2>
<ul>
<c:forEach var="username" items="${usernames}">
<li>${username}</li>
</c:forEach>
</ul>
</body>
</html>
优势:
- 分离关注点:业务逻辑在 Servlet 和 DAO 中处理,JSP 仅负责展示。
- 易于维护:修改业务逻辑无需更改 JSP 页面。
- 更好的连接管理:通过 DAO 和连接池统一管理连接。
常见问题及解决方案
连接未关闭导致资源泄漏
问题描述: Connection、Statement 或 ResultSet 未正确关闭,可能导致数据库连接池耗尽,影响应用性能。
解决方案:

- 始终在
finally块中关闭资源,或使用try-with-resources。 - 避免在多个地方获取同一连接而不关闭。
- 使用连接池管理连接生命周期。
异常处理导致连接未关闭
问题描述: 在捕获异常后,如果未在 finally 块中关闭连接,可能导致资源泄漏。
解决方案:
- 确保在所有异常情况下都能执行资源关闭代码。
- 使用
try-with-resources语法简化资源管理。 - 记录异常日志以便调试。
相关问答 FAQs
问题 1:为什么推荐使用连接池而不是直接在 JSP 中管理数据库连接?
解答: 使用连接池可以显著提高应用程序的性能和稳定性,连接池通过复用已有的数据库连接,减少了频繁建立和关闭连接的开销,连接池还提供了连接管理和监控功能,如最大连接数限制、空闲连接回收等,有助于防止资源泄漏和应用崩溃,相比之下,直接在 JSP 中管理连接容易导致代码冗余、难以维护以及资源管理不当的问题。
问题 2:在使用 try-with-resources 时,是否需要显式调用 close() 方法?
解答: 不需要。try-with-resources 语法会自动关闭实现了 AutoCloseable 接口的资源,在 try 代码块结束时,无论是否发生异常,都会自动调用资源的 close() 方法。
