杰瑞科技汇

java插入mysql中文乱码

下面我将从根本原因排查步骤解决方案(从最推荐到备选)三个方面,为你详细讲解如何解决这个问题。

java插入mysql中文乱码-图1
(图片来源网络,侵删)

根本原因:字符集不一致

想象一下你的中文数据("你好")要经过以下旅程才能存入数据库:

  1. Java 代码:字符串 "你好" 在内存中,它有一个默认的编码(通常是 JVM 启动时操作系统的编码,UTF-8)。
  2. JDBC 驱动:JDBC 驱动将这个字符串转换成一种能在网络上传输的格式(字节流)。
  3. MySQL 服务器:服务器接收这些字节流,并根据它自己的配置来“解释”这些字节,将其转换成数据库内部使用的字符。
  4. MySQL 数据库/表/列:数据被存储到指定数据库、表、列中,这些层级都有各自的字符集设置。

乱码发生的本质就是:数据在某个环节被用 A 编码写入了,但在另一个环节却被用 B 编码读取了。 数据被用 GBK 编码写入了,但 MySQL 却用 UTF-8 去解读,自然就会得到一堆看不懂的乱码。

要解决这个问题,必须确保从 Java 代码到 MySQL 数据库的每一个环节都使用统一的字符集,强烈推荐 UTF-8


排查步骤(如何找到问题点)

在动手修改之前,先按照以下步骤排查,确定问题出在哪一步。

检查 MySQL 数据库、表、列的字符集

这是最常见的问题点,登录到你的 MySQL 服务器,执行以下命令:

-- 1. 检查 MySQL 服务器默认的字符集
SHOW VARIABLES LIKE 'character_set_server';
-- 2. 检查当前数据库的字符集
USE your_database_name;
SHOW VARIABLES LIKE 'character_set_database';
-- 3. 检查表的字符集
SHOW CREATE TABLE your_table_name;
-- 4. 检查列的字符集 (你的 name 列)
SHOW FULL COLUMNS FROM your_table_name LIKE 'name';

关键点:

  • character_set_servercharacter_set_database 最好是 utf8mb4
  • SHOW CREATE TABLE 的结果中,表定义里应该有 DEFAULT CHARSET=utf8mb4
  • 列的 Collation(校对规则)应该以 utf8mb4 开头,utf8mb4_general_ciutf8mb4_unicode_ci

如果这些显示的不是 utf8mb4,那么很可能是问题所在。

检查 JDBC 连接 URL

这是第二个最常见的问题点,确保你的 JDBC URL 中明确指定了字符集。

错误示例: jdbc:mysql://localhost:3306/your_database

正确示例(推荐): jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8

重要提示: 从 JDBC 驱动 1.20 版本开始,characterEncoding 参数在某些情况下可能被忽略,更推荐使用 serverTimezone 参数,它通常会间接处理字符集问题,并且能避免时区问题。

更现代、更推荐的 URL 写法: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

检查 Java 源文件编码

确保你的 Java 源文件(.java 文件)本身是以 UTF-8 编码保存的。

  • IDE (如 IntelliJ IDEA / Eclipse):检查 IDE 的文件编码设置,确保是 UTF-8,在 IDEA 中,可以通过 File -> Settings -> Editor -> File Encodings 查看。
  • 命令行编译:如果使用 javac 命令编译,确保指定了编码:javac -encoding UTF-8 YourJavaFile.java

检查项目构建工具(Maven/Gradle)

如果你的项目使用 Maven 或 Gradle,确保编译和运行时都使用 UTF-8

Maven (pom.xml):

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

Gradle (build.gradle):

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

解决方案(从最推荐到备选)

统一使用 utf8mb4(强烈推荐)

utf8mb4utf8 的超集,它完全兼容 utf8,并且能够存储更多的字符,包括 Emoji 表情和一些罕见的汉字。这是目前业界公认的最佳实践。

修改 MySQL 数据库

如果你是新项目,在建库时直接指定字符集:

CREATE DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

如果你已有数据库,修改其字符集:

ALTER DATABASE your_database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

修改 MySQL 表

在建表时指定字符集:

CREATE TABLE your_table_name (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

对于已存在的表,修改字符集:

ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

注意CONVERT TO 会尝试将现有数据从旧编码转换到新编码,如果数据已经是乱码,这个转换也无法恢复,所以最好的时机是在数据出现乱码之前进行。

修改 JDBC URL

使用推荐的 URL 格式:

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

检查 Java 源码和构建工具 按照第二部分的“排查步骤”确保 Java 源码、IDE、Maven/Gradle 都配置为 UTF-8


统一使用 gbk(不推荐,仅作为备选)

如果你的数据库、应用环境、操作系统等所有环节都强制要求使用 GBK 编码,那么你需要将所有环节都统一为 GBK,但这会增加维护成本,并且无法支持 UTF-8 的字符集,通常不推荐。

修改 JDBC URL:

// 注意:这里的字符集是 GBK
String url = "jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=GBK&serverTimezone=Asia/Shanghai";

修改 MySQL: 数据库、表、列的字符集都需要设置为 gbk


在 Java 代码中进行硬编码转换(不推荐,最后手段)

这种方法治标不治本,只在无法修改数据库配置或 URL 的极端情况下使用,它非常脆弱,容易出错。

原理:在将字符串传给 JDBC 之前,手动将其编码成 GBK 的字节数组,再让 JDBC 驱动按 GBK 解读。

import java.nio.charset.StandardCharsets;
String originalName = "你好";
// 假设数据库是 GBK 编码
byte[] gbkBytes = originalName.getBytes("GBK"); // 手动编码成 GBK
String gbkName = new String(gbkBytes, "GBK"); // 创建一个 GBK 编码的字符串对象
// 然后将 gbkName 传给 PreparedStatement
// pstmt.setString(1, gbkName); 

缺点:代码臃肿,可读性差,如果未来数据库字符集变了,所有这些代码都要改,非常容易出错。


总结与最佳实践

要彻底解决 Java 插入 MySQL 中文乱码问题,请遵循以下黄金法则

  1. 首选字符集:在整个技术栈中全面拥抱 utf8mb4
  2. 数据库层:创建数据库和表时,显式指定 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
  3. 连接层:JDBC URL 必须包含 ?useUnicode=true&characterEncoding=UTF-8,并加上 serverTimezone
  4. 应用层:确保 Java 源文件、IDE、Maven/Gradle 的编码都是 UTF-8
  5. 驱动版本:尽量使用较新版本的 MySQL Connector/J 驱动。

只要确保了以上五点,你的中文数据就能在整个“数据链路”中畅通无阻,不再出现乱码问题。

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