Servlet 数据库访问
一、什么是 Servlet 数据库访问?
Servlet 数据库访问是指在 Servlet 中通过 Java Database Connectivity (JDBC) API 连接和操作数据库,实现数据的增删改查(CRUD)。这在 Web 应用中非常常见,例如用户注册、登录验证或数据查询。JDBC 是 Java 连接数据库的标准接口,支持多种数据库如 MySQL、Oracle 等。
本教程假设您已了解 JDBC 基础,并配置好数据库驱动(如 MySQL 的 mysql-connector-java.jar)。如果未配置,请先下载驱动并添加到项目 classpath 中。
二、JDBC 在 Servlet 中的基本流程
Servlet 访问数据库的典型流程包括:
- 加载驱动:使用
Class.forName()
加载 JDBC 驱动。 - 建立连接:通过
DriverManager.getConnection()
获取数据库连接。 - 创建语句:使用
Connection
创建Statement
或PreparedStatement
执行 SQL。 - 执行操作:查询(
executeQuery()
)或更新(executeUpdate()
)。 - 处理结果:对于查询,使用
ResultSet
读取数据。 - 关闭资源:关闭
ResultSet
、Statement
和Connection
以释放资源。
这些步骤需要在 Servlet 的 doGet()
或 doPost()
方法中实现。
三、Servlet 数据库访问的操作示例
以下以 MySQL 数据库为例,演示如何在 Servlet 中连接数据库并进行查询和插入操作。假设数据库名为 test
,表名为 users
(字段:id、name、age)。
1. 配置数据库驱动
- 下载 MySQL Connector/J(例如 mysql-connector-java-8.0.x.jar)。
- 在 Eclipse 或 IntelliJ 中,将 jar 包添加到项目的 Build Path 或 lib 目录。
2. 查询操作示例
创建一个 Servlet 来查询用户列表。
代码示例:
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.IOException;
import java.sql.*;
public class QueryServlet extends HttpServlet {
// 数据库连接信息
private static final String URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 建立连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
// 创建语句
stmt = conn.createStatement();
// 执行查询
String sql = "SELECT * FROM users";
rs = stmt.executeQuery(sql);
// 处理结果
out.println("<h1>用户列表</h1><ul>");
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
out.println("<li>ID: " + id + ", Name: " + name + ", Age: " + age + "</li>");
}
out.println("</ul>");
} catch (Exception e) {
out.println("错误: " + e.getMessage());
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
说明:
Class.forName("com.mysql.cj.jdbc.Driver")
:加载 MySQL 驱动(适用于 MySQL 8+)。DriverManager.getConnection()
:连接数据库,URL 中添加useUnicode=true&characterEncoding=UTF-8
支持中文。- 使用
try-catch-finally
处理异常和关闭资源。
3. 插入操作示例
使用 PreparedStatement
防止 SQL 注入。
代码示例:
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.IOException;
import java.sql.*;
public class InsertServlet extends HttpServlet {
private static final String URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
private static final String USER = "root";
private static final String PASSWORD = "your_password";
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USER, PASSWORD);
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name);
pstmt.setInt(2, age);
int rows = pstmt.executeUpdate();
out.println("插入成功,影响行数: " + rows);
} catch (Exception e) {
out.println("错误: " + e.getMessage());
} finally {
try {
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
说明:
PreparedStatement
使用占位符?
预编译 SQL,提高安全性和效率。request.setCharacterEncoding("UTF-8")
:处理 POST 请求中的中文参数。
四、处理中文数据库访问
在 Servlet 中访问数据库时,中文可能出现乱码问题。解决方案:
- 数据库配置:确保数据库和表使用 UTF-8 编码(例如
CREATE DATABASE test CHARACTER SET utf8mb4;
)。 - 连接 URL:添加
?useUnicode=true&characterEncoding=UTF-8
。 - 请求/响应编码:
request.setCharacterEncoding("UTF-8")
和response.setContentType("text/html;charset=UTF-8")
。 - 读取数据:
rs.getString("name")
时,如果数据库编码正确,无需额外处理。
示例:在插入中文姓名时,确保参数正确编码,即可避免乱码。
五、注意事项
- 安全性:
- 始终使用
PreparedStatement
防止 SQL 注入。 - 不要在代码中硬编码密码;使用配置文件或环境变量。
- 性能优化:
- 使用连接池(如 HikariCP 或 Tomcat JDBC Pool)代替每次创建连接,提高效率。
- 在 web.xml 或代码中配置数据源。
- 异常处理:
- 捕获
SQLException
和ClassNotFoundException
。 - 确保 finally 块关闭资源,避免连接泄漏。
- 数据库兼容:
- 不同数据库驱动不同(如 Oracle 使用 “oracle.jdbc.OracleDriver”)。
- 测试环境:本地 MySQL,生产环境可能使用云数据库(如 Google Cloud SQL)。
- 部署:
- 在 Tomcat 等容器中,确保驱动 jar 在 lib 目录。
- 对于大型应用,考虑使用 ORM 框架如 Hibernate 代替纯 JDBC。
六、常见问题与解决方案
- 问题:ClassNotFoundException: com.mysql.cj.jdbc.Driver。
- 解决:检查驱动 jar 是否添加到 classpath。
- 问题:中文乱码。
- 解决:检查连接 URL、请求编码和数据库字符集。
- 问题:连接超时。
- 解决:使用连接池,并设置超时参数。
七、总结
Servlet 通过 JDBC 实现数据库访问是 Web 开发的核心技能。从连接到执行 SQL,再到结果处理,整个过程需注重安全和效率。使用 PreparedStatement 和连接池可以显著提升应用质量。实际开发中,可结合 JSP 或框架如 Spring 来构建完整应用。