杰瑞科技汇

Java连接MySQL为何中文乱码?

问题根源:编码“接力赛”中的脱节

你可以把数据从你的 Java 应用程序最终显示在浏览器或控制台的过程,想象成一场“接力赛”,每一个环节都必须使用相同的“语言”(字符编码),否则就会出现乱码。

数据流向图: Java 代码 -> JDBC 驱动 -> MySQL 连接 -> MySQL 服务端 -> MySQL 数据库 -> MySQL 表 -> MySQL 字段 -> 数据返回 -> JDBC 驱动 -> Java 程序

只要在任何一个环节的编码设置不一致,乱码就可能发生。


常见乱码场景分析

场景 1:存入数据库时乱码(存进去就错了)

  • 现象:在 Java 程序中打印中文是正常的,但存入数据库后,查看表数据发现是问号 或一堆乱码。
  • 原因:通常是 Java 应用程序 -> MySQL 数据库 这个环节的编码不一致,最常见的组合是:
    • Java 程序:使用 UTF-8 编码。
    • MySQL 服务端/连接:使用 latin1(MySQL 默认编码)。

场景 2:从数据库读取时乱码(取出来就错了)

  • 现象:直接在 MySQL 客户端(如 Navicat, HeidiSQL)里看数据是正常的,但用 Java 程序查询出来并打印后,显示为乱码。
  • 原因:通常是 MySQL 数据库 -> Java 应用程序 这个环节的编码不一致,可能是因为数据库连接的 characterEncoding 参数没有正确设置,或者 JDBC 驱动在返回数据时没有使用正确的编码。

场景 3:Java 程序内部乱码(代码或 IDE 问题)

  • 现象:Java 源代码中的字符串字面量本身就是乱码。
  • 原因
    1. 源文件编码.java 源文件本身的保存编码不是 UTF-8
    2. IDE 编码:IDE(如 IntelliJ IDEA, Eclipse)的默认项目编码设置和源文件编码不一致。

终极解决方案:全链路 UTF-8 配置

要彻底解决乱码,最推荐、最可靠的方法是 将整个数据链路统一设置为 UTF-8

步骤 1:检查并修改 MySQL 服务端配置

这是最关键的一步,你需要确保 MySQL 服务器本身、默认的数据库和字符集都使用 utf8mb4

utf8mb4 vs utf8

  • utf8:MySQL 中的一个“伪” UTF-8 编码,它最多只能支持 3 个字节的字符,无法存储一些 Emoji 表情或某些生僻的汉字。
  • utf8mb4:真正的 UTF-8 编码,使用 1 到 4 个字节来存储字符,完全兼容 utf8,并且能支持所有 Unicode 字符。强烈推荐使用 utf8mb4

如何修改?

  1. 查看当前配置: 在 MySQL 客户端中执行以下命令:

    -- 查看服务器级别的字符集
    SHOW VARIABLES LIKE 'character_set_server';
    SHOW VARIABLES LIKE 'collation_server';
    -- 查看数据库级别的字符集
    SHOW CREATE DATABASE your_database_name;
    -- 查看表级别的字符集
    SHOW CREATE TABLE your_table_name;
  2. 修改配置文件(永久生效): 编辑 MySQL 的配置文件(根据你的系统不同,路径可能不同):

    • Linux: /etc/my.cnf/etc/mysql/my.cnf
    • Windows: my.ini (通常在 MySQL 安装目录下)

    [mysqld][client] 部分添加或修改以下配置:

    [mysqld]
    # 设置服务器默认字符集为 utf8mb4
    character-set-server = utf8mb4
    # 设置默认排序规则
    collation-server = utf8mb4_unicode_ci
    # 确保连接层也使用 utf8mb4
    init_connect='SET NAMES utf8mb4'
    [client]
    # 设置客户端默认字符集
    default-character-set = utf8mb4
  3. 重启 MySQL 服务: 保存配置文件后,重启 MySQL 服务使配置生效。

  4. 修改现有数据库和表: 如果你的数据库或表已经存在且不是 utf8mb4,需要进行转换。

    -- 修改数据库的字符集
    ALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    -- 修改表的字符集
    ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    -- 修改表中字段的字符集
    ALTER TABLE your_table_name MODIFY your_column_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

步骤 2:配置 Java 连接字符串 (JDBC URL)

在 Java 代码中,连接字符串必须明确指定编码,这是告诉 JDBC 驱动如何与 MySQL 通信的“语言”。

错误示例(可能导致乱码):

String url = "jdbc:mysql://localhost:3306/your_database";

正确示例(明确指定编码):

String url = "jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8";

最佳实践(推荐 utf8mb4):

String url = "jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8mb4";
  • useUnicode=true: 启用 Unicode 字符集。
  • characterEncoding=utf8mb4: 指定连接使用的字符编码为 utf8mb4

步骤 3:确保 Java 源代码和 IDE 编码为 UTF-8

  1. 源文件编码: 确保你的 .java 文件在保存时就是 UTF-8 编码,大多数现代 IDE 默认就是 UTF-8,但最好确认一下。

  2. IDE 项目编码设置

    • IntelliJ IDEA:
      1. File -> Settings -> Editor -> File Encodings
      2. Global EncodingProject EncodingDefault encoding for properties files 都设置为 UTF-8
    • Eclipse:
      1. Window -> Preferences -> General -> Workspace
      2. Text file encoding 设置为 UTF-8
      3. Window -> Preferences -> General -> Content Types
      4. Java Source File 上,确保 Default encodingUTF-8,然后点击 Update

代码示例(最佳实践)

下面是一个完整的、遵循上述最佳实践的 Java 连接 MySQL 的示例代码。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class MysqlEncodingTest {
    // 数据库连接信息
    // 注意:URL 中明确指定了 characterEncoding=utf8mb4
    private static final String DB_URL = "jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=utf8mb4";
    private static final String DB_USER = "your_username";
    private static final String DB_PASSWORD = "your_password";
    public static void main(String[] args) {
        // 1. 插入测试数据
        insertData("你好,世界!这是一个测试。");
        // 2. 查询并打印测试数据
        selectAndPrintData();
    }
    public static void insertData(String chineseText) {
        // 使用 try-with-resources 确保 Connection, PreparedStatement 自动关闭
        String sql = "INSERT INTO your_table_name (your_column_name) VALUES (?)";
        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, chineseText);
            int affectedRows = pstmt.executeUpdate();
            System.out.println("成功插入 " + affectedRows + " 行数据。");
        } catch (SQLException e) {
            System.err.println("插入数据时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
    public static void selectAndPrintData() {
        String sql = "SELECT your_column_name FROM your_table_name ORDER BY id DESC LIMIT 1";
        try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            if (rs.next()) {
                // getString() 方法会自动使用 JDBC URL 中指定的编码来解码
                String retrievedText = rs.getString("your_column_name");
                System.out.println("从数据库读取到的数据: " + retrievedText);
            }
        } catch (SQLException e) {
            System.err.println("查询数据时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

总结与排错清单

如果按照以上步骤操作后仍有乱码,请按以下清单逐一排查:

  1. MySQL 服务端

    • [mysqld] 配置文件中的 character-set-server 是否为 utf8mb4
    • 数据库、表、字段的 CHARACTER SET 是否为 utf8mb4
  2. JDBC 连接字符串

    • URL 中是否包含了 ?useUnicode=true&characterEncoding=utf8mb4?这是最容易遗漏的地方。
  3. Java 应用层

    • IDE 的项目编码和文件编码是否为 UTF-8
    • Java 源文件本身是否以 UTF-8 保存?(可以用记事本等工具打开看是否正常)
  4. 数据传输层

    • 确保你使用的 JDBC 驱动版本较新(建议 8.0.x 以上版本,对 utf8mb4 支持更好)。

遵循 “全链路 UTF-8” 的原则,并确保每个环节的配置都正确,99% 的中文乱码问题都可以迎刃而解。

分享:
扫描分享到社交APP
上一篇
下一篇