目录
- 准备工作
- 安装 MySQL 数据库
- 创建测试数据库和表
- 安装 Java 开发环境 (JDK)
- 核心步骤:获取数据库连接
- 使用 JDBC 驱动(传统方式)
- 使用构建工具(Maven/Gradle)管理依赖(推荐方式)
- 编写 Java 代码进行 CRUD 操作
- 加载驱动与建立连接
- 创建
Statement或PreparedStatement - 执行 SQL 语句
- 处理结果集 (
ResultSet) - 关闭资源
- 完整代码示例
增、删、改、查 示例
(图片来源网络,侵删) - 最佳实践与注意事项
- 使用
PreparedStatement防止 SQL 注入 - 使用
try-with-resources自动关闭资源 - 使用连接池
- 配置信息分离
- 使用
准备工作
在开始之前,请确保你已经安装并配置好了以下环境:
a. 安装 MySQL 数据库
确保你的电脑上已经安装了 MySQL 数据库,并且服务正在运行,你可以从 MySQL 官网 下载安装。
b. 创建测试数据库和表
登录到你的 MySQL 客户端(如 MySQL Workbench, Navicat, 或命令行),执行以下 SQL 语句来创建一个用于测试的数据库和表。
-- 创建一个名为 'test_db' 的数据库
CREATE DATABASE IF NOT EXISTS test_db;
-- 使用这个数据库
USE test_db;
-- 创建一个 'users' 表
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
email VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入一些测试数据
INSERT INTO users (username, password, email) VALUES
('zhangsan', '123456', 'zhangsan@example.com'),
('lisi', '654321', 'lisi@example.com');
c. 安装 Java 开发环境 (JDK)
确保你已经安装了 JDK(Java Development Kit),并且配置好了 JAVA_HOME 环境变量和 PATH 路径,你可以通过在命令行运行 java -version 和 javac -version 来检查。

核心步骤:获取数据库连接
Java 通过 JDBC (Java Database Connectivity) API 来与数据库进行交互,要连接 MySQL,你需要一个 MySQL JDBC 驱动程序。
手动下载 JDBC 驱动(不推荐)
- 下载驱动:访问 MySQL Connector/J 下载页面。
- 选择版本:选择一个与你的 MySQL 和 JDK 版本兼容的驱动包,通常选择 Platform Independent (Architecture Independent), ZIP Archive 格式。
- 添加到项目:将下载的
.jar文件(mysql-connector-j-8.0.xx.jar)添加到你的 Java 项目的类路径(Classpath)中。- 在 IDE (如 IntelliJ IDEA/Eclipse) 中:右键项目 -> Build Path / Project Structure -> Libraries -> Add External JARs...
- 在命令行编译时:使用
-cp或-classpath参数指定.jar文件的路径。
使用构建工具(Maven/Gradle)管理依赖(强烈推荐)
这种方式更简单、更规范,可以自动处理依赖版本和下载。
如果你使用 Maven,在你的 pom.xml 文件中添加以下依赖:
<dependencies>
<!-- MySQL Connector/J -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 建议使用较新的稳定版本 -->
</dependency>
</dependencies>
Maven 会自动下载所需的驱动包并管理它。
编写 Java 代码进行 CRUD 操作
我们开始写 Java 代码,一个标准的数据库操作流程如下:
- 加载驱动:告诉 JVM 我们要使用哪个数据库的驱动。
- 建立连接:使用
DriverManager的getConnection()方法,传入数据库的 URL、用户名和密码。 - 创建 Statement:通过
Connection对象创建一个Statement或PreparedStatement对象,用于执行 SQL 语句。 - 执行 SQL:调用
Statement的executeQuery()(用于查询) 或executeUpdate()(用于增删改) 方法。 - 处理结果:如果是查询,会返回一个
ResultSet对象,你需要遍历这个结果集来获取数据。 - 关闭资源:按照
ResultSet->Statement->Connection的顺序关闭所有资源,以释放数据库连接。
连接 URL 格式
MySQL 的连接 URL 有一个标准的格式:
jdbc:mysql://[host][:port]/[database][?property1=value1&property2=value2]
host:数据库服务器的地址,如localhost或0.0.1。port:端口号,MySQL 默认是3306。database:要连接的数据库名,如test_db。properties:可选的连接属性。
示例 URL:
jdbc:mysql://localhost:3306/test_db
对于较新版本的 MySQL (8.0+),推荐在 URL 中指定时区,以避免一些警告:
jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC
完整代码示例
下面是一个完整的 Java 类,演示了如何连接数据库并进行增、删、改、查操作。
重要提示:请将代码中的数据库用户名和密码替换为你自己的。
import java.sql.*;
public class MysqlJdbcExample {
// 数据库连接信息
private static final String DB_URL = "jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC";
private static final String USER = "root"; // 你的数据库用户名
private static final String PASS = "your_password"; // 你的数据库密码
public static void main(String[] args) {
// --- 查询示例 ---
System.out.println("--- 查询所有用户 ---");
selectAllUsers();
// --- 插入示例 ---
System.out.println("\n--- 插入新用户 'wangwu' ---");
insertUser("wangwu", "password123", "wangwu@example.com");
selectAllUsers(); // 再次查询以验证插入
// --- 更新示例 ---
System.out.println("\n--- 更新用户 'zhangsan' 的密码 ---");
updateUserPassword("zhangsan", "new_password_789");
selectAllUsers(); // 再次查询以验证更新
// --- 删除示例 ---
System.out.println("\n--- 删除用户 'lisi' ---");
deleteUser("lisi");
selectAllUsers(); // 再次查询以验证删除
}
/**
* 查询所有用户
*/
public static void selectAllUsers() {
// 使用 try-with-resources 自动关闭资源
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, username, email FROM users")) {
System.out.println("ID\tUsername\tEmail");
System.out.println("---------------------------------");
while (rs.next()) {
// 通过列名获取数据,更具可读性
int id = rs.getInt("id");
String username = rs.getString("username");
String email = rs.getString("email");
System.out.printf("%d\t%s\t\t%s\n", id, username, email);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 插入一个新用户
*/
public static void insertUser(String username, String password, String email) {
// 使用 ? 作为占位符,防止 SQL 注入
String sql = "INSERT INTO users (username, password, email) VALUES (?, ?, ?)";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
// 使用 PreparedStatement 来执行带参数的 SQL
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数
pstmt.setString(1, username);
pstmt.setString(2, password);
pstmt.setString(3, email);
// 执行更新
int affectedRows = pstmt.executeUpdate();
System.out.println("成功插入 " + affectedRows + " 行数据。");
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 更新指定用户的密码
*/
public static void updateUserPassword(String username, String newPassword) {
String sql = "UPDATE users SET password = ? WHERE username = ?";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, newPassword);
pstmt.setString(2, username);
int affectedRows = pstmt.executeUpdate();
System.out.println("成功更新 " + affectedRows + " 行数据。");
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* 删除指定用户
*/
public static void deleteUser(String username) {
String sql = "DELETE FROM users WHERE username = ?";
try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username);
int affectedRows = pstmt.executeUpdate();
System.out.println("成功删除 " + affectedRows + " 行数据。");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
最佳实践与注意事项
a. 使用 PreparedStatement 防止 SQL 注入
永远不要使用字符串拼接来构建 SQL 语句,这极易导致 SQL 注入攻击,从而危及你的数据安全。
错误示例:
String username = "admin' OR '1'='1"; String sql = "SELECT * FROM users WHERE username = '" + username + "'"; // 危险!
正确做法: 始终使用 PreparedStatement 和 占位符。PreparedStatement 会对传入的参数进行转义处理,从根本上杜绝 SQL 注入。
String sql = "SELECT * FROM users WHERE username = ?";
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username); // 安全地设置参数
// ...
}
b. 使用 try-with-resources 自动关闭资源
从 Java 7 开始,try-with-resources 语句可以确保实现了 AutoCloseable 接口(如 Connection, Statement, ResultSet)的资源在 try 块执行完毕后自动关闭,即使发生异常也是如此,这极大地简化了代码,并避免了资源泄漏。
// 推荐
try (Connection conn = ...) {
// 使用 conn
} // conn 自动关闭
// 不推荐(旧式写法)
Connection conn = null;
try {
conn = ...
// ...
} catch (Exception e) {
// ...
} finally {
if (conn != null) {
try { conn.close(); } catch (SQLException e) { /* ... */ }
}
}
c. 使用连接池
在真实的应用中,频繁地创建和销毁数据库连接是非常消耗性能的。连接池 应运而生,它预先创建一组数据库连接,并将其保存在一个池中,当需要连接时,从池中获取一个,使用完毕后,将其归还到池中,而不是直接关闭。
常用的 Java 连接池:
- HikariCP: 目前性能最好的连接池,是 Spring Boot 2.x 的默认选择。
- Apache DBCP: Apache 组织提供的连接池。
- C3P0: 一个老牌但仍然广泛使用的连接池。
使用连接池后,你不再直接通过 DriverManager 获取连接,而是从连接池中获取。
d. 配置信息分离
不要将数据库 URL、用户名、密码等敏感信息直接硬编码在 Java 代码中,这会使代码难以维护,并且存在安全风险。
推荐做法:
- 将这些配置信息放在一个外部的配置文件中(如
config.properties或application.yml)。 - 在 Java 代码中读取这个配置文件。
示例 (config.properties):
db.url=jdbc:mysql://localhost:3306/test_db?serverTimezone=UTC db.username=root db.password=your_password
示例 (Java 代码读取):
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
public class DbUtil {
public static Connection getConnection() throws Exception {
Properties props = new Properties();
// 从类路径下加载配置文件
try (InputStream input = DbUtil.class.getClassLoader().getResourceAsStream("config.properties")) {
if (input == null) {
throw new RuntimeException("Sorry, unable to find config.properties");
}
props.load(input);
}
String url = props.getProperty("db.url");
String user = props.getProperty("db.username");
String pass = props.getProperty("db.password");
return DriverManager.getConnection(url, user, pass);
}
} 