杰瑞科技汇

Java Java Oracle中文乱码怎么解决?

乱码的根本原因

乱码的本质是 “编码和解码所使用的字符集不一致”

Java Oracle中文乱码怎么解决?-图1
(图片来源网络,侵删)

想象一下:

  • 发送方 (Java):把一串中文字符(如 "你好")按照 编码A(如 GBK)转换成一串二进制数据(E4 BD A0 E5 A5 BD)。
  • 接收方 (Oracle):接收到这串二进制数据后,却按照 编码B(如 ISO-8859-1)去解析,试图还原成文字,由于 E4 BD A0ISO-8859-1 中找不到对应的字符,于是就显示成了乱码(如 )。

我们的目标就是确保从 Java 应用到 Oracle 数据库的整个链路中,所有环节都使用 同一种字符集


完整排查与解决方案(从易到难)

请按照以下步骤逐一排查,通常问题都能解决。

步骤 1:检查数据库服务端的字符集

这是最根本的设置,数据库的字符集决定了它能正确存储和显示哪些语言。

Java Oracle中文乱码怎么解决?-图2
(图片来源网络,侵删)
  1. 登录到 Oracle 数据库

    sqlplus / as sysdba
  2. 查询数据库字符集

    SELECT value$ FROM sys.props$ WHERE name = 'NLS_CHARACTERSET';
    • 推荐字符集AL32UTF8,这是 Oracle 推荐的字符集,完全兼容 Unicode,可以存储世界上几乎所有语言的字符,是解决国际化问题的首选。
    • 常见问题字符集ZHS16GBKWE8ISO8859P1ZHS16GBK 只支持中文和少数亚洲语言,而 WE8ISO8859P1 基本不支持中文,非常容易出乱码。

如果数据库字符集不是 AL32UTF8,并且业务有国际化需求,强烈建议在合适的时候进行字符集迁移(这是一个复杂的操作,需要谨慎规划)。

步骤 2:检查 JDBC 连接 URL 的字符集设置

这是最直接、最常用的解决方案,在 JDBC 连接字符串中显式指定客户端和服务器之间的字符集。

Java Oracle中文乱码怎么解决?-图3
(图片来源网络,侵删)

问题 URL:

String url = "jdbc:oracle:thin:@localhost:1521:ORCL";

修正后的 URL (推荐使用 AL32UTF8):

// 显式指定使用 AL32UTF8 字符集进行通信
String url = "jdbc:oracle:thin:@localhost:1521:ORCL?useUnicode=true&characterEncoding=UTF-8";
// 如果数据库是 ZHS16GBK,则指定为 GBK
// String url = "jdbc:oracle:thin:@localhost:1521:ORCL?useUnicode=true&characterEncoding=GBK";

参数解释:

  • useUnicode=true: 告诉 JDBC 驱动使用 Unicode 字符流。
  • characterEncoding=UTF-8 (或 GBK): 指定 Java 应用程序与数据库之间网络传输时使用的字符编码。这个编码最好和数据库服务端的字符集保持一致

最佳实践:将数据库字符集设置为 AL32UTF8,JDBC URL 也使用 characterEncoding=UTF-8,这样整个系统都基于 Unicode,兼容性最好。

步骤 3:检查 Java 源代码文件的编码

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

  • IDE (如 IntelliJ IDEA, Eclipse) 设置
    • 在 IDE 的设置中,将项目文件的默认编码设置为 UTF-8
    • 确保编译时使用的也是 UTF-8 编码,对于 Maven 项目,可以在 pom.xml 中指定:
      <properties>
          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
          <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      </properties>
  • 编译命令行
    • 使用 -encoding UTF-8 参数进行编译:
      javac -encoding UTF-8 YourJavaFile.java

如果源文件编码不对,比如用 GBK 保存了代码,但编译器默认按 UTF-8 解析,那么代码里的中文注释或字符串本身就可能变成乱码。

步骤 4:检查 Web 应用的响应编码

如果你的 Java 应用是一个 Web 项目(如 Spring Boot, Servlet),除了从数据库读,还要确保输出到浏览器时编码正确。

  1. 设置 Response 编码: 在 Servlet 的 doGetdoPost 方法中,或者在框架的过滤器中,设置响应的字符编码。

    // 方式一:Servlet API
    response.setContentType("text/html;charset=UTF-8");
    response.setCharacterEncoding("UTF-8");
    // 方式二:Spring Boot (推荐在配置文件或配置类中全局设置)
    # application.properties
    server.servlet.encoding.charset=UTF-8
    server.servlet.encoding.enabled=true
    server.servlet.encoding.force=true
  2. 检查 HTML/JSP 页面

    • HTML <meta>:在 HTML 文件的 <head> 部分添加:
      <meta charset="UTF-8">
    • JSP 页面
      <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

步骤 5:检查 Oracle 客户端工具的编码

如果你使用 SQL*Plus, PL/SQL Developer, DBeaver 等工具连接数据库并查询数据,这些工具本身也有字符集设置。

  • *SQLPlus**:

    在 Windows 上,SQL*Plus 的窗口字体可能不支持 UTF-8,可以尝试修改其属性中的字体,或者使用更现代的客户端工具。

  • PL/SQL Developer
    • Tools -> Preferences -> Connection -> Oracle Client:确保你的 Oracle 客户端路径正确。
    • Tools -> Preferences -> Connection -> SQL Window:可以尝试设置 NLS_LANG 环境变量,SIMPLIFIED CHINESE_CHINA.AL32UTF8
  • DBeaver
    • Database -> Driver Manager -> [你的 Oracle 驱动] -> Edit:在 Advanced Settings 中,可以设置 Session Init SQLALTER SESSION SET NLS_LANGUAGE='SIMPLIFIED CHINESE'; ALTER SESSION SET NLS_TERRITORY='CHINA';

最佳实践方案

为了从根本上杜绝中文乱码问题,推荐采用以下 “三统一” 方案:

  1. 统一数据库字符集

    • 将 Oracle 数据库的 NLS_CHARACTERSET 设置为 AL32UTF8,这是最核心的一步。
  2. 统一 JDBC 连接编码

    • 在 JDBC URL 中明确指定字符集:
      jdbc:oracle:thin:@host:port:sid?useUnicode=true&characterEncoding=UTF-8
  3. 统一应用编码

    • 源代码:所有 .java 文件保存为 UTF-8 编码。
    • Web 项目:在响应头和页面中统一使用 UTF-8
    • 项目构建:Maven/Gradle 项目配置文件编码为 UTF-8

特殊情况:已存乱码数据的修复

如果你的数据库中已经存在乱码数据,修复起来会比较麻烦,因为乱码数据是“不可逆”的,你无法知道 原本是什么字。

修复思路:你需要知道当初是 “用 A 编码存储,却用 B 编码读取”,然后反过来,用 “B 编码写入,用 A 编码读取” 来“纠正”它。

示例场景

  • 数据库字符集是 WE8ISO8859P1
  • JDBC URL 没有指定编码,导致 Java 用系统默认编码(如 GBK)发送中文,数据库用 ISO-8859-1 存储,导致乱码。
  • 数据库里存的乱码是 。

修复步骤

  1. 创建一个临时表,字符集和原表一致。
  2. 使用正确的编码进行“纠正”插入
    -- 假设乱码列是 name VARCHAR2(100)
    -- 原始编码是GBK,存储成了ISO-8859-1
    -- 现在我们用ISO-8859-1去解释这些乱码字节,再转换成GBK插入
    INSERT INTO temp_table (id, corrected_name)
    SELECT id, 
           UTL_I18N.STRING_TO_CHAR(
               UTL_RAW.CAST_TO_VARCHAR2(UTL_I18N.CHAR_TO_RAW(name, 'WE8ISO8859P1')), 
               'ZHS16GBK'
           )
    FROM original_table;

    这个 SQL 语句非常复杂且容易出错,请务必在测试环境充分验证。

更推荐的做法:对于已经乱码的数据,如果业务允许,最好的方式是重新从数据源获取正确的数据,然后清空表重新导入,如果无法重新获取,那么就需要根据上述原理进行非常谨慎的修复操作。

希望这份详细的指南能帮助你解决 Java Oracle 中文乱码问题!

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