杰瑞科技汇

Java如何连接MySQL数据库?

目录

  1. 准备工作
  2. 核心概念:JDBC
  3. 使用 JDBC 驱动(传统方式)
    • 步骤详解
    • 完整代码示例
    • 优缺点分析
  4. 使用连接池(推荐方式)
    • 什么是连接池?
    • 使用 HikariCP(目前性能最好的连接池)
    • 完整代码示例
  5. 最佳实践与注意事项
    • 务必使用 try-with-resources
    • 务必使用 PreparedStatement
    • 配置文件管理
    • 异常处理
  6. 如何选择?

准备工作

在开始写 Java 代码之前,请确保你已经准备好了以下环境:

Java如何连接MySQL数据库?-图1
(图片来源网络,侵删)
  • Java 开发环境 (JDK): 确保你的系统已经安装了 JDK 并且配置了 JAVA_HOME 环境变量。
  • MySQL 数据库: 安装并运行着 MySQL 服务器。
  • MySQL 数据和用户:
    • 创建一个用于测试的数据库,test_db
    • 在该数据库中创建一张表,users
    • 创建一个可以访问该数据库的用户,java_user,并设置密码(password123)。
    • 给该用户授予 test_db 数据库的访问权限。
  • MySQL JDBC 驱动: 这是 Java 连接 MySQL 的桥梁,你需要下载对应的驱动 Jar 包。
    • 下载地址: MySQL Connector/J
    • 选择平台无关的版本(Platform Independent),下载一个 .zip.tar.gz 文件。
    • 解压后,你会找到一个名为 mysql-connector-j-版本号.jar 的文件,这个就是我们需要的驱动。

核心概念:JDBC

JDBC (Java Database Connectivity) 是 Java API,它定义了客户端如何访问数据库,它本身并不实现数据库连接,而是提供了一套标准接口,数据库厂商(如 MySQL、Oracle)会提供这些接口的实现,也就是我们下载的 JDBC 驱动

JDBC 是 Java 与数据库沟通的“通用语言”。


方法一:使用 JDBC 驱动(传统方式)

这是最基础的方式,理解它有助于你理解连接的本质。

步骤详解

  1. 加载 JDBC 驱动: 使用 Class.forName() 将驱动类的实现加载到 JVM 中。
  2. 获取数据库连接: 使用 DriverManager.getConnection() 方法,提供数据库的 URL、用户名和密码来建立连接。
  3. 创建 Statement 对象: 通过连接对象创建一个 StatementPreparedStatement 对象,用于执行 SQL 语句。
  4. 执行 SQL 查询: 调用 Statement 对象的 executeQuery() 方法(用于查询)或 executeUpdate() 方法(用于增删改)。
  5. 处理结果集: 如果是查询操作,会返回一个 ResultSet 对象,你需要遍历它来获取数据。
  6. 关闭资源: 非常重要! 按照创建的逆序关闭所有资源:ResultSet -> Statement -> Connection,如果不关闭,会导致数据库连接泄漏,最终耗尽数据库资源。

完整代码示例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcExample {
    // 数据库连接信息 (硬编码不推荐,仅作演示)
    private static final String DB_URL = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC";
    private static final String USER = "java_user";
    private static final String PASS = "password123";
    public static void main(String[] args) {
        // 1. 加载 JDBC 驱动 (MySQL 8+ 的驱动类名)
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.err.println("找不到 MySQL JDBC 驱动,请确保驱动在 classpath 中。");
            e.printStackTrace();
            return;
        }
        // try-with-resources 语句 (Java 7+),可以自动关闭资源
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
            System.out.println("成功连接到数据库!");
            System.out.println("ID\tName\tEmail");
            // 3. 遍历结果集
            while (rs.next()) {
                // 通过列名获取数据,更具可读性且不易出错
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (SQLException e) {
            System.err.println("数据库连接或查询出错!");
            e.printStackTrace();
        }
    }
}

如何运行

  1. 将下载的 mysql-connector-j-版本号.jar 文件复制到你的项目目录下。
  2. 如果你使用 IDE(如 IntelliJ IDEA 或 Eclipse),右键点击这个 Jar 文件,选择 "Add as Library" 或 "Add to Build Path"。
  3. 运行 JdbcExample.java

优缺点分析

  • 优点: 简单直接,易于理解。
  • 缺点:
    • 性能差: 每次请求都创建一个新的连接,销毁一个连接,开销巨大。
    • 资源浪费: 高并发下会迅速耗尽数据库的连接资源。
    • 代码冗余: 每次连接都需要重复加载驱动、建立连接的代码。

方法二:使用连接池(推荐方式)

为了解决传统方式的性能问题,我们引入 数据库连接池

Java如何连接MySQL数据库?-图2
(图片来源网络,侵删)

什么是连接池?

连接池是一个管理数据库连接的“池子”,应用程序启动时,它会预先创建一定数量的连接并放入池中,当需要连接时,从池中“借用”一个,用完后“归还”给池子,而不是销毁,这样就避免了频繁创建和销毁连接的开销,极大地提升了性能。

使用 HikariCP(目前性能最好的连接池)

HikariCP 是目前公认性能最高、稳定性最好的 JDBC 连接池。

添加依赖

如果你使用 Maven,在 pom.xml 中添加 HikariCP 和 MySQL 驱动的依赖:

Java如何连接MySQL数据库?-图3
(图片来源网络,侵删)
<dependencies>
    <!-- HikariCP 连接池 -->
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>5.0.1</version> <!-- 使用最新版本 -->
    </dependency>
    <!-- MySQL JDBC 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version> <!-- 使用与数据库匹配的版本 -->
    </dependency>
</dependencies>

如果你使用 Gradle,在 build.gradle 中添加:

dependencies {
    // HikariCP 连接池
    implementation 'com.zaxxer:HikariCP:5.0.1'
    // MySQL JDBC 驱动
    implementation 'com.mysql:mysql-connector-j:8.0.33'
}

完整代码示例

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 HikariCPExample {
    // 使用 HikariDataSource 作为数据源
    private static HikariDataSource dataSource;
    // 静态代码块,在类加载时初始化连接池
    static {
        HikariConfig config = new HikariConfig();
        // --- 配置信息 ---
        config.setJdbcUrl("jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC");
        config.setUsername("java_user");
        config.setPassword("password123");
        // 连接池配置
        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 void main(String[] args) {
        // 从连接池获取一个连接
        try (Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT id, name, email FROM users")) {
            System.out.println("成功从连接池获取连接!");
            System.out.println("ID\tName\tEmail");
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                System.out.println(id + "\t" + name + "\t" + email);
            }
        } catch (SQLException e) {
            System.err.println("从连接池获取连接或查询出错!");
            e.printStackTrace();
        }
        // 在应用程序关闭时,关闭连接池
        if (dataSource != null && !dataSource.isClosed()) {
            dataSource.close();
        }
    }
}

最佳实践与注意事项

务必使用 try-with-resources

从 Java 7 开始,try-with-resources 语句可以自动实现 AutoCloseable 接口的资源关闭。强烈推荐使用它,它能确保 Connection, Statement, ResultSet 等资源在任何情况下都会被正确关闭,即使发生异常。

// 推荐
try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
    // ...
} catch (SQLException e) {
    // ...
}
// 不推荐(容易忘记关闭)
Connection conn = null;
PreparedStatement pstmt = null;
try {
    conn = dataSource.getConnection();
    pstmt = conn.prepareStatement("...");
} catch (SQLException e) {
    // ...
} finally {
    // 必须手动关闭,且要处理嵌套的 try-catch
    if (pstmt != null) try { pstmt.close(); } catch (SQLException e) { /* log */ }
    if (conn != null) try { conn.close(); } catch (SQLException e) { /* log */ }
}

务必使用 PreparedStatement

PreparedStatement 是预编译的 SQL 语句,它有两大好处:

  1. 防止 SQL 注入: 它会将参数作为数据处理,而不是 SQL 代码的一部分,从而有效防止恶意 SQL 注入攻击。
  2. 性能更好: 对于需要多次执行的 SQL(只是参数不同),数据库可以重用预编译的执行计划,提高效率。
// 使用 Statement (不安全)
String sql = "SELECT * FROM users WHERE name = '" + userName + "'";
// userName 是 "admin' OR '1'='1",SQL 就会被篡改。
// 使用 PreparedStatement (安全)
String sql = "SELECT * FROM users WHERE name = ?";
try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    pstmt.setString(1, userName); // 将 userName 作为参数设置
    // ...
}

配置文件管理

不要将数据库 URL、用户名、密码等敏感信息硬编码在代码中,应该放在外部配置文件(如 application.propertiesconfig.properties)中。

config.properties 文件:

db.url=jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC
db.user=java_user
db.password=password123
db.pool.size=10

然后在 Java 代码中读取这个文件。

异常处理

数据库操作可能会因为网络问题、SQL 语法错误、权限问题等抛出 SQLException,你应该妥善捕获并处理这些异常,例如记录日志,而不是简单地 printStackTrace()


如何选择?

特性 JDBC 驱动 (传统方式) 连接池 (如 HikariCP)
性能 ,频繁创建/销毁连接 ,复用连接,性能优异
资源管理 差,容易泄漏 ,自动管理连接的生命周期
适用场景 简单的、一次性的脚本或测试 所有生产环境、Web 应用、高并发场景
代码复杂度 简单 稍复杂,但配置后一劳永逸
  • 学习和测试时: 可以使用传统的 JDBC 方式,帮助你理解底层原理。
  • 任何实际项目(尤其是生产环境): 必须使用连接池,HikariCP 是目前的首选。必须结合 try-with-resourcesPreparedStatement 来编写健壮、安全、高效的数据库访问代码。
分享:
扫描分享到社交APP
上一篇
下一篇