跳到主要内容
Java Web 开发实战:数据库操作与会话技术 | 极客日志
Java java
Java Web 开发实战:数据库操作与会话技术 介绍 Java Web 开发中的数据库操作与会话管理。涵盖 MySQL 基础 CRUD 操作、JDBC 连接及 PreparedStatement 防注入、C3P0 连接池配置使用,以及 Cookie 和 Session 的原理、区别与代码实现。重点讲解如何通过 JDBC 连接 MySQL,利用连接池优化性能,并使用 Cookie/Session 维护用户状态。
游戏玩家 发布于 2026/4/6 更新于 2026/6/4 31 浏览四、Java Web 开发中的数据库操作:以 MySQL 为例
4.1 MySQL 数据库基础操作
MySQL 作为一种广泛使用的开源关系型数据库管理系统,在 Java Web 开发中扮演着数据存储与管理的重要角色。理解并掌握 MySQL 的基础操作是进行 Java Web 数据库开发的基石。
数据库在 MySQL 中是数据存储与组织的核心容器,用于存放各类数据。创建数据库时,使用 CREATE DATABASE 语句,语法为 CREATE DATABASE [IF NOT EXISTS] database_name;。其中,IF NOT EXISTS 为可选参数,用于避免在数据库已存在时抛出错误。例如,创建一个名为 testdb 的数据库,代码如下:
CREATE DATABASE IF NOT EXISTS testdb;
若要切换当前操作的数据库,使用 USE 语句,如 USE testdb;。查看所有数据库,可执行 SHOW DATABASES;,它会列出系统中所有的数据库。而当某个数据库不再需要时,可使用 DROP DATABASE 语句删除,如 DROP DATABASE testdb;,但此操作需谨慎,因为一旦执行,数据库及其所有数据将被永久删除。
表是数据库中数据存储的具体结构,类似于货架,每个货架存放特定类型的数据。创建表时,需定义表名及各列的名称、数据类型和约束条件。例如,创建一个名为 users 的表,用于存储用户信息,包含 id(用户 ID,整数类型,自动递增且为主键)、username(用户名,可变长度字符串,最大长度为 50)、email(邮箱,可变长度字符串,最大长度为 100)和 password(密码,可变长度字符串,最大长度为 50),代码如下:
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY , username VARCHAR (50 ), email VARCHAR (100 ), password VARCHAR (50 ) );
查看数据库中的所有表,执行 SHOW TABLES;。若要查看某个表的结构,使用 DESCRIBE 语句,如 DESCRIBE users;,它会详细列出表中各列的信息。当表不再需要时,使用 DROP TABLE 语句删除,如 DROP TABLE users;,同样会删除表及其所有数据。
在数据库中插入数据是常见操作。向 users 表中插入一条用户数据,包含用户名 john_doe、邮箱 [email protected] 和密码 password123,代码如下:
INSERT INTO users (username, email, password) VALUES ('john_doe' , '[email protected] ' , 'password123' );
若要插入多条数据,可在 VALUES 关键字后用逗号分隔多个值列表:
INSERT INTO users (username, email, password) VALUES ('jane_smith' , '[email protected] ' , 'password456' ), ('tom_wilson' , , );
'password789'
从数据库中查询数据是获取信息的关键操作。查询 users 表中所有用户的信息,使用 SELECT 语句:
这里的 * 表示选择所有列。若只查询部分列,如只查询 username 和 email 列,代码为:
SELECT username, email FROM users;
若要根据条件查询,如查询用户名为 john_doe 的用户信息,使用 WHERE 子句:
SELECT * FROM users WHERE username = 'john_doe' ;
还可以对查询结果进行排序,如按 username 升序排序:
SELECT * FROM users ORDER BY username ASC ;
删除数据库中的数据用于移除不再需要的记录。删除 users 表中用户名为 tom_wilson 的用户记录:
DELETE FROM users WHERE username = 'tom_wilson' ;
4.2 JDBC 技术深度解析 JDBC(Java Database Connectivity)是 Java 语言中用于连接和操作数据库的重要 API,它为 Java 开发者提供了一种统一的方式来与各种不同类型的数据库进行交互。
JDBC 的核心接口和常用类构成了其强大功能的基础。DriverManager 类负责管理数据库驱动程序的加载和建立数据库连接。例如,在加载 MySQL 数据库驱动时,使用 Class.forName("com.mysql.cj.jdbc.Driver"); 语句。
Connection 接口代表与数据库的连接。通过 DriverManager.getConnection(url, username, password) 方法获取连接对象,其中 url 为数据库连接字符串,username 和 password 分别为数据库的用户名和密码。例如:
String url = "jdbc:mysql://localhost:3306/testdb" ;
String username = "root" ;
String password = "password" ;
Connection connection = DriverManager.getConnection(url, username, password);
Statement 接口用于执行 SQL 语句。通过 Connection 对象的 createStatement() 方法创建 Statement 对象。然后使用 statement.executeQuery(sql) 方法执行查询语句,返回 ResultSet 结果集;使用 statement.executeUpdate(sql) 方法执行插入、更新、删除等语句,返回受影响的行数。
PreparedStatement 接口继承自 Statement 接口,主要用于执行预编译的 SQL 语句。预编译的 SQL 语句可以提高执行效率,并且能有效防止 SQL 注入攻击。通过 Connection 对象的 prepareStatement(sql) 方法创建 PreparedStatement 对象,其中 sql 为带有参数占位符(?)的 SQL 语句。例如,插入用户数据的预编译 SQL 语句为:
String sql = "INSERT INTO users (username, email, password) VALUES (?,?,?)" ;
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1 , "new_user" );
preparedStatement.setString(2 , "[email protected] " );
preparedStatement.setString(3 , "new_password" );
int rowsAffected = preparedStatement.executeUpdate();
ResultSet 接口用于存储查询结果集。通过 Statement 或 PreparedStatement 执行查询语句后返回 ResultSet 对象,然后使用 while (resultSet.next()) 循环遍历结果集,通过 resultSet.getString("column_name") 等方法获取指定列的值。
接下来,我们通过一个完整的代码示例来展示如何使用 JDBC 连接 MySQL 数据库并执行查询操作:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcExample {
public static void main (String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb" ;
String username = "root" ;
String password = "password" ;
try {
Class.forName("com.mysql.cj.jdbc.Driver" );
Connection connection = DriverManager.getConnection(url, username, password);
Statement statement = connection.createStatement();
String sql = "SELECT * FROM users" ;
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int id = resultSet.getInt("id" );
String usernameFromDb = resultSet.getString("username" );
String email = resultSet.getString("email" );
System.out.println("ID: " + id + ", Username: " + usernameFromDb + ", Email: " + email);
}
resultSet.close();
statement.close();
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在使用 JDBC 过程中,可能会遇到一些常见问题。例如,驱动程序未找到异常 ClassNotFoundException,这通常是因为没有正确添加数据库驱动包或驱动类名写错。还有连接数据库失败的问题,可能是由于连接字符串错误、用户名或密码错误、数据库服务器未启动等原因导致。SQL 注入攻击也是一个需要关注的问题,使用 PreparedStatement 代替 Statement 可以有效防止 SQL 注入攻击。
4.3 数据库连接池的应用 在 Java Web 开发中,频繁地创建和销毁数据库连接会带来显著的性能开销。数据库连接池技术应运而生,它通过预先创建一定数量的数据库连接,并将这些连接存储在连接池中,当应用程序需要与数据库进行交互时,可以直接从连接池中获取一个可用的连接,而不需要每次都重新建立连接。
常见的数据库连接池有 HikariCP、C3P0、DBCP 等。HikariCP 以其高性能和低延迟著称。C3P0 是一个老牌的 Java 数据库连接池,具有较高的稳定性和可靠性。DBCP 是 Apache Commons 项目的一部分,具有简单易用、配置灵活等特点。
接下来,我们以 C3P0 为例,展示如何配置和使用数据库连接池。首先,需要在项目中添加 C3P0 的依赖。如果使用 Maven 项目,在 pom.xml 文件中添加以下依赖:
<dependency >
<groupId > com.mchange</groupId >
<artifactId > c3p0</artifactId >
<version > 0.9.5.5</version >
</dependency >
然后,在 src 目录下创建 c3p0-config.xml 配置文件,进行连接池的配置,示例代码如下:
<c3p0-config >
<default-config >
<property name ="driverClass" > com.mysql.cj.jdbc.Driver</property >
<property name ="jdbcUrl" > jdbc:mysql://localhost:3306/testdb</property >
<property name ="user" > root</property >
<property name ="password" > password</property >
<property name ="acquireIncrement" > 5</property >
<property name ="initialPoolSize" > 5</property >
<property name ="minPoolSize" > 5</property >
<property name ="maxPoolSize" > 10</property >
<property name ="autoCommitOnClose" > false</property >
<property name ="idleConnectionTestPeriod" > 60</property >
<property name ="maxIdleTime" > 300</property >
</default-config >
</c3p0-config >
在上述配置文件中,设置了数据库驱动类、连接 URL、用户名、密码等基本信息,还配置了连接池的一些属性。
接下来,通过代码获取连接池中的连接并执行数据库操作,示例代码如下:
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class C3P0Example {
public static void main (String[] args) {
ComboPooledDataSource dataSource = new ComboPooledDataSource ();
try {
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver" );
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/testdb" );
dataSource.setUser("root" );
dataSource.setPassword("password" );
dataSource.setMinPoolSize(5 );
dataSource.setMaxPoolSize(10 );
dataSource.setCheckoutTimeout(3000 );
Connection connection = null ;
PreparedStatement preparedStatement = null ;
ResultSet resultSet = null ;
try {
connection = dataSource.getConnection();
String sql = "SELECT * FROM users" ;
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int id = resultSet.getInt("id" );
String username = resultSet.getString("username" );
String email = resultSet.getString("email" );
System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email);
}
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
if (resultSet != null ) { try { resultSet.close(); } catch (SQLException ex) { ex.printStackTrace(); } }
if (preparedStatement != null ) { try { preparedStatement.close(); } catch (SQLException ex) { ex.printStackTrace(); } }
if (connection != null ) { try { connection.close(); } catch (SQLException ex) { ex.printStackTrace(); } }
}
} catch (PropertyVetoException ex) {
ex.printStackTrace();
} finally {
dataSource.close();
}
}
}
五、Java Web 中的会话技术:Cookie 与 Session
5.1 Cookie 详解 Cookie 是一种客户端会话管理技术,它就像是服务器发给客户端浏览器的一张小纸条,用于在客户端存储少量数据。当用户访问服务器时,服务器可以将一些信息以 Cookie 的形式发送给浏览器,浏览器会将这些 Cookie 存储在本地。当下次用户再次访问服务器时,浏览器会自动将这些 Cookie 发送给服务器。
会话状态管理:例如用户登录信息的记录。
个性化设置:存储用户的个性化设置,如语言偏好、主题风格等。
购物车功能:在电商网站中,存储用户购物车中的商品信息。
在 Java 中,操作 Cookie 主要使用 javax.servlet.http.Cookie 类。常用的属性和方法如下:
属性:name(名称)、value(值)、maxAge(最大生存时间)、path(路径)、domain(域名)、secure(是否仅 HTTPS)、httpOnly(是否只能通过 HTTP(S) 访问)。
常用方法:Cookie(String name, String value)、setMaxAge(int expiry)、getName()、getValue()、setValue(String value)、setPath(String path) 等。
下面通过代码示例来展示如何创建、发送和获取 Cookie:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/cookieExample")
public class CookieExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie cookie = new Cookie ("username" , "John" );
cookie.setMaxAge(3600 );
cookie.setPath("/" );
response.addCookie(cookie);
response.getWriter().println("Cookie has been set." );
}
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
上述代码创建了一个名为 username,值为 John 的 Cookie,并设置了它的最大生存时间为 1 小时,路径为根路径,然后将其添加到响应中发送给客户端。
在另一个 Servlet 中获取 Cookie 的代码如下:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/getCookieExample")
public class GetCookieExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cookies = request.getCookies();
if (cookies != null ) {
for (Cookie cookie : cookies) {
if ("username" .equals(cookie.getName())) {
String username = cookie.getValue();
response.getWriter().println("Username from Cookie: " + username);
break ;
}
}
}
}
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
需要注意的是,在设置 Cookie 的路径时,要根据实际需求进行设置。此外,Cookie 的大小有限制,每个 Cookie 通常不能超过 4KB,并且浏览器对同一个域名下的 Cookie 数量也有限制。
5.2 Session 详解 Session 是一种服务端会话管理技术,它为每个用户的浏览器创建一个独享的会话空间,用于在服务器端存储用户的会话数据。当用户访问服务器时,服务器会为其创建一个 Session 对象,并分配一个唯一的 Session ID。这个 Session ID 通常会通过 Cookie 发送给客户端浏览器,浏览器在后续的请求中会将这个 Session ID 发送回服务器。
用户首次访问服务器时,服务器会创建一个新的 Session 对象,并生成一个唯一的 Session ID。
服务器将 Session ID 通过 Cookie 发送给客户端浏览器,这个 Cookie 的名称通常为 JSESSIONID。
客户端浏览器在后续的请求中,会将包含 JSESSIONID 的 Cookie 发送回服务器。
服务器接收到请求后,根据 Cookie 中的 JSESSIONID 找到对应的 Session 对象,从而获取该用户的会话数据。
Session 的主要作用是在一次会话中,为用户提供一个可以在不同页面或请求之间共享数据的空间。例如,在一个电商网站中,用户在浏览商品时将商品添加到购物车,这些购物车中的商品信息就可以存储在 Session 中。
在 Java 中,操作 Session 主要通过 HttpSession 接口。常用的方法如下:
getSession():获取当前请求的 Session 对象。
setAttribute(String name, Object value):在 Session 中存储一个属性。
getAttribute(String name):从 Session 中获取指定属性名的属性值。
removeAttribute(String name):从 Session 中移除指定属性名的属性。
getId():获取 Session 的唯一标识符。
setMaxInactiveInterval(int interval):设置 Session 的最大非活动间隔时间。
invalidate():使当前 Session 失效。
下面通过代码示例来展示如何创建、获取和销毁 Session,以及在 Session 中保存和获取数据:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/sessionExample")
public class SessionExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
session.setAttribute("username" , "John" );
String sessionId = session.getId();
response.getWriter().println("Session ID: " + sessionId);
response.getWriter().println("Username saved in Session: " + session.getAttribute("username" ));
session.setMaxInactiveInterval(1800 );
}
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
上述代码获取当前请求的 Session 对象,在 Session 中保存了一个名为 username,值为 John 的属性,并输出了 Session ID 和保存的用户名。同时,设置了 Session 的最大非活动间隔时间为 30 分钟。
在另一个 Servlet 中获取 Session 数据的代码如下:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/getSessionExample")
public class GetSessionExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false );
if (session != null ) {
String username = (String) session.getAttribute("username" );
response.getWriter().println("Username from Session: " + username);
} else {
response.getWriter().println("Session does not exist." );
}
}
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
这段代码获取当前请求的 Session 对象(如果不存在则不创建),并从 Session 中获取名为 username 的属性值进行输出。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/destroySessionExample")
public class DestroySessionExampleServlet extends HttpServlet {
private static final long serialVersionUID = 1L ;
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false );
if (session != null ) {
session.invalidate();
response.getWriter().println("Session has been destroyed." );
} else {
response.getWriter().println("Session does not exist." );
}
}
protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
这段代码获取当前请求的 Session 对象(如果不存在则不创建),并调用 invalidate 方法使 Session 失效,即销毁 Session 及其存储的所有属性。
Session 与 Cookie 有着密切的关系,Session 的实现依赖于 Cookie 来传递 Session ID。如果客户端禁用了 Cookie,那么 Session ID 就无法通过 Cookie 发送回服务器,服务器也就无法识别用户的会话。为了解决这个问题,可以采用 URL 重写的方式,将 Session ID 附加在 URL 后面进行传递。例如,原本的 URL 为 http://example.com/page,经过 URL 重写后变为 http://example.com/page;jsessionid=1234567890,这样服务器仍然可以根据 URL 中的 Session ID 来识别用户的会话。不过,这种方式存在一定的安全风险,因为 Session ID 暴露在 URL 中,可能会被恶意用户窃取和利用,所以在实际应用中,应尽量确保客户端启用 Cookie 来传递 Session ID,以提高系统的安全性。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online