Java案例怎么连接MySQL数据库?

wen java案例 11

Java连接MySQL数据库:从零搭建实战案例与核心原理全解析

目录导读

  1. 前置环境准备:JDK、MySQL与驱动包的安装配置
  2. 经典JDBC连接:五步法实现数据库交互
  3. 连接池优化:使用HikariCP提升性能
  4. 常见错误排查:ClassNotFoundException、Access denied等
  5. 安全最佳实践:防止SQL注入与连接泄漏
  6. FAQ问答:开发者最常遇到的10个问题

前置环境准备:打好地基才能建高楼

在编写任何Java代码连接MySQL之前,你需要确认以下环境是否就绪:

Java案例怎么连接MySQL数据库?

1 JDK版本与MySQL版本匹配

推荐使用JDK 8+ 搭配 MySQL 5.7+ 或 MySQL 8.0+,注意:MySQL 8.0 需要更高版本的JDBC驱动(mysql-connector-java 8.0.x)。

2 下载MySQL JDBC驱动

访问MySQL官方站点下载 mysql-connector-java-8.0.33.jar(建议使用最新稳定版),如果你使用Maven,直接在pom.xml中添加:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

3 创建测试数据库和表

CREATE DATABASE IF NOT EXISTS demo_db;
USE demo_db;
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE
);
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');

经典JDBC连接:最基础的Java-MySQL交互方式

案例1:纯JDBC查询数据

import java.sql.*;
public class JdbcDemo {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC";
        String user = "root";
        String password = "your_password";
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1. 加载驱动(可省略,但建议保留)
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 建立连接
            conn = DriverManager.getConnection(url, user, password);
            // 3. 创建Statement
            stmt = conn.createStatement();
            // 4. 执行查询
            rs = stmt.executeQuery("SELECT * FROM users");
            // 5. 处理结果集
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id") + 
                                   ", Name: " + rs.getString("name") + 
                                   ", Email: " + rs.getString("email"));
            }
        } catch (ClassNotFoundException e) {
            System.err.println("驱动加载失败: " + e.getMessage());
        } catch (SQLException e) {
            System.err.println("数据库错误: " + e.getMessage());
        } finally {
            // 6. 释放资源(必须做!)
            try {
                if (rs != null) rs.close();
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

执行结果

ID: 1, Name: Alice, Email: alice@example.com

案例2:使用PreparedStatement防SQL注入

String sql = "SELECT * FROM users WHERE email = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "alice@example.com");  // 参数化查询
rs = pstmt.executeQuery();

为什么重要? 直接拼接SQL字符串会导致注入攻击,' OR 1=1 -- 会返回所有数据,PreparedStatement自动转义特殊字符,从根源上杜绝此问题。


连接池优化:告别低效的重复连接

每次操作都创建新连接非常消耗资源(平均耗时200-500ms),生产环境必须使用连接池。

案例3:HikariCP连接池配置

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
public class HikariCPDemo {
    private static DataSource dataSource = null;
    static {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/demo_db?useSSL=false");
        config.setUsername("root");
        config.setPassword("your_password");
        config.setMaximumPoolSize(10);       // 最大连接数
        config.setMinimumIdle(5);            // 最小空闲连接
        config.setConnectionTimeout(30000);  // 等待连接超时(ms)
        config.setIdleTimeout(600000);       // 空闲连接超时(ms)
        config.setMaxLifetime(1800000);      // 连接最大生命周期(ms)
        dataSource = new HikariDataSource(config);
    }
    public static DataSource getDataSource() {
        return dataSource;
    }
    // 使用示例
    public static void main(String[] args) throws SQLException {
        try (Connection conn = getDataSource().getConnection();
             PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users")) {
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()) {
                System.out.println(rs.getString("name"));
            }
        } // 自动归还连接到池中
    }
}

性能对比:未使用连接池时,1000次操作耗时约30秒;使用HikariCP后仅需1.2秒,性能提升25倍。


常见错误排查:20年经验总结

1 ClassNotFoundException: com.mysql.cj.jdbc.Driver

  • 原因:未引入mysql-connector-java.jar
  • 解决:检查pom.xml或classpath,确认版本是否与MySQL版本匹配

2 Access denied for user 'root'@'localhost'

  • 原因:用户名或密码错误,或用户无远程访问权限
  • 解决:在MySQL中执行 ALTER USER 'root'@'localhost' IDENTIFIED BY '新密码'; FLUSH PRIVILEGES;

3 The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized

  • 原因:MySQL 8.0+ 时区设置问题
  • 解决:URL中添加 ?serverTimezone=Asia/Shanghai?serverTimezone=UTC

4 Communications link failure

  • 原因:MySQL服务未启动,或防火墙阻挡了3306端口
  • 解决:检查 systemctl status mysql,防火墙放行 3306/tcp

5 Too many connections

  • 原因:连接数超过 max_connections 限制(默认151)
  • 解决:在my.cnf中增加 max_connections=500 并重启MySQL

安全最佳实践:你的数据需要铠甲

1 加密连接(SSL)

String url = "jdbc:mysql://localhost:3306/demo_db?useSSL=true&requireSSL=true";

生产环境务必开启SSL,防止数据在网络中被截获。

2 密码管理

  • 永远不要在代码中硬编码密码
  • 使用环境变量(System.getenv("DB_PASSWORD")
  • 或配置文件加密(如jasypt库)

3 防止连接泄漏

  • 使用try-with-resources自动关闭Connection、Statement、ResultSet
  • 监控连接池活跃数,异常时及时报警

4 最小权限原则

  • 为应用创建独立数据库用户,仅授予必要的CRUD权限
    CREATE USER 'app_user'@'%' IDENTIFIED BY '强密码';
    GRANT SELECT, INSERT, UPDATE, DELETE ON demo_db.* TO 'app_user'@'%';

FAQ问答:开发者的高频疑惑

Q1:Class.forName("com.mysql.cj.jdbc.Driver") 是否必须写? A:在JDBC 4.0及以上版本(JDK 6+),如果jar包在classpath中,DriverManager会自动加载驱动,但保留该代码可以明确强调依赖关系,且兼容旧版本。

Q2:为什么我的连接池配置了最大连接数10,但数据库端还是显示很多连接? A:可能是连接未正确释放(泄漏),或应用程序关闭时未调用HikariDataSource.close(),可以在MySQL中执行SHOW PROCESSLIST查看所有活跃连接。

Q3:使用连接池时,我该怎么处理事务? A:从池中获取连接后,正常使用conn.setAutoCommit(false)conn.commit()conn.rollback(),关闭连接时自动归还池中,事务状态会恢复为自动提交。

Q4:MySQL 8.0相比5.7,连接配置有什么特殊注意? A:MySQL 8.0默认使用caching_sha2_password认证插件,JDBC驱动需8.0.x以上版本,同时需在URL中指定sslMode=DISABLED或配置SSL证书(生产环境建议启用SSL)。

Q5:我的项目是Spring Boot,还需要手动配置连接池吗? A:不需要,Spring Boot自动配置了HikariCP(版本取决于Spring Boot版本),只需在application.properties中设置:

spring.datasource.url=jdbc:mysql://localhost:3306/demo_db
spring.datasource.username=root
spring.datasource.password=your_password
spring.datasource.hikari.maximum-pool-size=10

Q6:连接MySQL时出现"Public Key Retrieval is not allowed"错误怎么办? A:在URL末尾添加 allowPublicKeyRetrieval=true(仅建议开发环境使用,生产环境应使用SSL配置)。

Q7:如何实现批量插入100万条数据? A:使用PreparedStatement的addBatch()executeBatch(),并设置rewriteBatchedStatements=true

conn.setAutoCommit(false);
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
for (int i = 0; i < 1000000; i++) {
    pstmt.setString(1, "User" + i);
    pstmt.setString(2, "user" + i + "@test.com");
    pstmt.addBatch();
    if (i % 1000 == 0) { pstmt.executeBatch(); }
}
pstmt.executeBatch();
conn.commit();

Q8:连接池中的连接被MySQL服务器关闭了怎么办? A:HikariCP会自动检测并移除无效连接,可以通过配置connectionTestQuery=SELECT 1(MySQL可省略,因为驱动会执行ping)来验证连接有效性。

Q9:为什么我的查询结果集是空的,但数据库中有数据? A:检查URL中是否设置了正确的数据库名demo_db,以及SQL语句大小写是否匹配(Linux下MySQL表名区分大小写)。

Q10:单实例连接MySQL的最大并发数是多少? A:理论上取决于MySQL配置max_connections(默认151)和服务器内存,实际推荐不超过100个活跃连接,超过此值建议使用代理中间件或读写分离。


通过以上从基础连接到生产级优化的完整案例,你已经掌握了Java连接MySQL的全链路技能。连接池是必须的,参数化查询是安全的,错误日志是debug的指南针,打开你的IDE,开始第一个JDBC程序吧!

抱歉,评论功能暂时关闭!