目录
- 准备工作
- 安装 MySQL 数据库
- 创建数据库和测试表
- 准备 Java 开发环境
- 核心步骤:获取 JDBC 驱动
- 编写 Java 连接代码
- 基础版(不推荐用于生产)
- 推荐版(使用
try-with-resources) - 使用配置文件(推荐)
- 执行 SQL 查询
- 查询数据 (
SELECT) - 更新数据 (
INSERT,UPDATE,DELETE)
- 查询数据 (
- 最佳实践
- 使用连接池
- 防止 SQL 注入
- 使用
PreparedStatement
- 完整示例代码
- 常见问题与解决
准备工作
a. 安装 MySQL 数据库
确保您的计算机上已经安装并运行了 MySQL 数据服务器,您可以从 MySQL 官网 下载并安装。

b. 创建数据库和测试表
打开 MySQL 命令行客户端或任何 MySQL GUI 工具(如 MySQL Workbench, Navicat, DBeaver),执行以下 SQL 语句来创建一个示例数据库和表。
-- 创建一个名为 'testdb' 的数据库
CREATE DATABASE IF NOT EXISTS testdb;
-- 使用 'testdb' 数据库
USE testdb;
-- 创建一个 'users' 表
CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
age INT
);
-- 插入一些测试数据
INSERT INTO users (name, email, age) VALUES
('Alice', 'alice@example.com', 30),
('Bob', 'bob@example.com', 25),
('Charlie', 'charlie@example.com', 35);
c. 准备 Java 开发环境
确保您已经安装了 JDK (Java Development Kit) 和一个 IDE(如 IntelliJ IDEA, Eclipse 或 VS Code)。
核心步骤:获取 JDBC 驱动
Java 通过 JDBC (Java Database Connectivity) API 来连接数据库,要连接 MySQL,您需要 MySQL 提供的 JDBC 驱动程序。
驱动程序类型:

- JDBC Type 4 (纯 Java 驱动): 这是最现代和推荐的类型,它不需要客户端库,直接使用网络套接字连接。
如何获取驱动程序? 您有两种主要方式:
使用 Maven(推荐)
如果您使用 Maven 管理项目,只需在 pom.xml 文件中添加以下依赖即可,Maven 会自动下载驱动。
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 建议使用最新版本 -->
</dependency>
手动下载 JAR 文件
- 访问 Maven Central Repository。
- 找到最新版本的
mysql-connector-j-8.0.33.jar(或您需要的版本)。 - 下载 JAR 文件。
- 将此 JAR 文件添加到您的 Java 项目的类路径 中,在 IDE 中,通常右键项目 -> Build Path / Project Structure -> Libraries -> Add External JARs。
编写 Java 连接代码
连接数据库需要以下信息:

- URL: 格式为
jdbc:mysql://[host][:port]/[database_name]host: 数据库服务器地址(本地为localhost或0.0.1)port: MySQL 端口(默认为3306)database_name: 要连接的数据库名(如testdb)
- User: 数据库用户名(如
root) - Password: 数据库密码
a. 基础版(不推荐用于生产)
这是最简单的写法,但存在严重问题:如果发生异常,Connection 对象不会被关闭,会导致数据库连接泄漏。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class BasicConnection {
public static void main(String[] args) {
// 数据库连接信息
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root";
String password = "your_password"; // 请替换为您的密码
Connection conn = null;
try {
// 1. 加载 JDBC 驱动 (对于较新版本的驱动,这一步通常可以省略)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 建立连接
System.out.println("正在连接数据库...");
conn = DriverManager.getConnection(url, user, password);
System.out.println("数据库连接成功!");
} catch (ClassNotFoundException e) {
System.err.println("找不到 MySQL JDBC 驱动。");
e.printStackTrace();
} catch (SQLException e) {
System.err.println("数据库连接失败!");
e.printStackTrace();
} finally {
// 3. 关闭连接 (非常重要!)
if (conn != null) {
try {
conn.close();
System.out.println("数据库连接已关闭。");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
b. 推荐版(使用 try-with-resources)
Java 7 引入了 try-with-resources 语句,它可以自动实现 AutoCloseable 接口的对象(如 Connection, Statement, ResultSet)在 try 块结束时自动关闭,极大地简化了资源管理,是当前的最佳实践。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ModernConnection {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/testdb";
String user = "root";
String password = "your_password"; // 请替换为您的密码
// try-with-resources 会自动关闭 conn
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("数据库连接成功!");
// 在这里执行数据库操作...
System.out.println("操作完成。");
} catch (SQLException e) {
System.err.println("数据库操作出错!");
e.printStackTrace();
}
// conn 在这里会被自动关闭
System.out.println("数据库连接已自动关闭。");
}
}
c. 使用配置文件(推荐)
将数据库连接信息硬编码在代码中是不好的做法,更好的方式是将其放在外部配置文件中。
-
在
src/main/resources目录下创建一个db.properties文件:src/main/resources/db.properties# 数据库连接配置 db.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC db.user=root db.password=your_password # 请替换为您的密码
?useSSL=false: 在本地开发时禁用 SSL(生产环境应配置 SSL)。&serverTimezone=UTC: 指定服务器时区,避免警告。
-
修改 Java 代码以读取配置文件:
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class ConfigurableConnection {
public static void main(String[] args) {
// 加载配置文件
Properties props = new Properties();
InputStream input = ConfigurableConnection.class.getClassLoader().getResourceAsStream("db.properties");
if (input == null) {
System.err.println("抱歉,找不到 db.properties 文件");
return;
}
try {
props.load(input);
} catch (IOException e) {
System.err.println("加载配置文件失败!");
e.printStackTrace();
return;
}
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String password = props.getProperty("db.password");
// 使用 try-with-resources
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("数据库连接成功!");
// ... 执行操作 ...
} catch (SQLException e) {
System.err.println("数据库操作出错!");
e.printStackTrace();
}
}
}
执行 SQL 查询
a. 查询数据 (SELECT)
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class SelectExample {
public static void main(String[] args) {
Properties props = new Properties();
try (InputStream input = SelectExample.class.getClassLoader().getResourceAsStream("db.properties")) {
props.load(input);
} catch (IOException e) {
e.printStackTrace();
return;
}
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String password = props.getProperty("db.password");
String sql = "SELECT id, name, email, age FROM users";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) { // executeQuery 用于 SELECT 语句
System.out.println("用户列表:");
System.out.println("---------------------------------");
while (rs.next()) { // 遍历结果集
// 通过列名获取数据,更具可读性
int id = rs.getInt("id");
String name = rs.getString("name");
String email = rs.getString("email");
int age = rs.getInt("age");
System.out.printf("ID: %d, 姓名: %s, 邮箱: %s, 年龄: %d%n", id, name, email, age);
}
System.out.println("---------------------------------");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
b. 更新数据 (INSERT, UPDATE, DELETE)
对于 INSERT, UPDATE, DELETE 等不返回结果集的语句,应使用 executeUpdate()。
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class UpdateExample {
public static void main(String[] args) {
Properties props = new Properties();
// ... (加载配置文件的代码与上面相同) ...
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String password = props.getProperty("db.password");
// 要执行的 SQL 语句
String sql = "UPDATE users SET age = ? WHERE name = ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
// 使用 PreparedStatement 来防止 SQL 注入
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 设置参数 (索引从 1 开始)
pstmt.setInt(1, 31); // 第一个 ? 设置为 31
pstmt.setString(2, "Alice"); // 第二个 ? 设置为 "Alice"
// 执行更新
int affectedRows = pstmt.executeUpdate();
System.out.println("更新操作完成,影响了 " + affectedRows + " 行。");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
最佳实践
a. 使用连接池
每次创建和销毁数据库连接都非常消耗资源,连接池(如 HikariCP, Apache DBCP, C3P0)可以复用已建立的数据库连接,显著提高性能。
使用 HikariCP (目前性能最好的连接池) 的示例:
-
Maven 依赖:
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> <!-- 使用最新版本 --> </dependency> -
代码:
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class ConnectionPoolExample { private static HikariDataSource dataSource; static { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"); config.setUsername("root"); config.setPassword("your_password"); config.setDriverClassName("com.mysql.cj.jdbc.Driver"); // 连接池配置 config.setMaximumPoolSize(10); // 最大连接数 config.setMinimumIdle(5); // 最小空闲连接数 config.setConnectionTimeout(30000); // 连接超时时间 (毫秒) config.setIdleTimeout(600000); // 空闲连接超时时间 config.setMaxLifetime(1800000); // 连接最大存活时间 dataSource = new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void main(String[] args) { try (Connection conn = getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT name FROM users")) { System.out.println("从连接池获取连接成功!"); while (rs.next()) { System.out.println(rs.getString("name")); } } catch (SQLException e) { e.printStackTrace(); } } }
b. 防止 SQL 注入
永远不要使用字符串拼接来构建 SQL 语句! 这会导致严重的 SQL 注入安全漏洞。
错误示例 (SQL 注入):
String userName = "admin' OR '1'='1"; // 恶意输入 String sql = "SELECT * FROM users WHERE name = '" + userName + "'"; // 危险!
正确做法:使用 PreparedStatement
PreparedStatement 会对输入参数进行转义,从而有效防止 SQL 注入,它也是预编译的 SQL 语句,对于多次执行相同 SQL(仅参数不同)的场景性能更好。
// 安全的做法
String sql = "SELECT * FROM users WHERE name = ?"; // 使用 ? 作为占位符
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, userName); // 安全地设置参数
ResultSet rs = pstmt.executeQuery();
// ...
}
完整示例代码
这是一个结合了配置文件、try-with-resources、PreparedStatement 和查询功能的完整示例。
UserDAO.java (数据访问对象)
import java.io.InputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class UserDAO {
private Connection getConnection() throws SQLException {
Properties props = new Properties();
try (InputStream input = getClass().getClassLoader().getResourceAsStream("db.properties")) {
if (input == null) {
throw new SQLException("无法找到 db.properties 文件");
}
props.load(input);
} catch (IOException e) {
throw new SQLException("加载配置文件失败", e);
}
String url = props.getProperty("db.url");
String user = props.getProperty("db.user");
String password = props.getProperty("db.password");
return DriverManager.getConnection(url, user, password);
}
public List<String> getAllUserNames() {
List<String> names = new ArrayList<>();
String sql = "SELECT name FROM users";
try (Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
names.add(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return names;
}
public void updateUserAge(String name, int newAge) {
String sql = "UPDATE users SET age = ? WHERE name = ?";
try (Connection conn = getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, newAge);
pstmt.setString(2, name);
int affectedRows = pstmt.executeUpdate();
System.out.println("更新年龄操作,影响了 " + affectedRows + " 行。");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Main.java (主程序)
public class Main {
public static void main(String[] args) {
UserDAO userDAO = new UserDAO();
// 1. 查询所有用户名
System.out.println("所有用户名:");
userDAO.getAllUserNames().forEach(System.out::println);
System.out.println("--------------------");
// 2. 更新用户年龄
System.out.println("将 Bob 的年龄更新为 26...");
userDAO.updateUserAge("Bob", 26);
System.out.println("--------------------");
// 3. 再次查询以验证更新
System.out.println("更新后的所有用户名:");
userDAO.getAllUserNames().forEach(System.out::println);
}
}
常见问题与解决
-
问题1:
No suitable driver found for jdbc:mysql://...- 原因: JDBC 驱动没有正确加载或添加到类路径。
- 解决: 确保您已经下载了
mysql-connector-j.jar并将其添加到项目的类路径中,如果您使用 Maven,请检查pom.xml中的依赖是否正确。
-
问题2:
Access denied for user 'root'@'localhost'- 原因: 用户名或密码错误,或者该用户没有权限访问
testdb数据库。 - 解决:
- 检查代码中的用户名和密码是否与 MySQL 中的设置一致。
- 登录 MySQL,使用
GRANT ALL PRIVILEGES ON testdb.* TO 'root'@'localhost';命令授权(如果需要)。
- 原因: 用户名或密码错误,或者该用户没有权限访问
-
问题3:
The server time zone value '�йʱ��' is unrecognized...- 原因: JDBC 驱动无法识别服务器返回的时区。
- 解决: 在 JDBC URL 中明确指定时区,在
db.properties中修改db.url:db.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC
或者根据您的时区设置为
Asia/Shanghai等。
-
问题4:
Communications link failure- 原因: 无法连接到 MySQL 服务器。
- 解决:
- 确认 MySQL 服务正在运行。
- 检查
host和port是否正确(默认localhost:3306)。 - 检查防火墙是否阻止了端口 3306。
希望这份详细的指南能帮助您顺利地在 Java 中连接 MySQL 数据库!
