<p>必须先查NLS_CHARACTERSET:SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET',结果只可能是AL32UTF8或ZHS16GBK;JDBC连接串需显式指定characterEncoding,且须与数据库字符集严格匹配。</p>
oracle 中文显示乱码,第一件事不是改 java 代码,而是确认数据库到底用什么字符集存数据。nls_characterset 才是唯一可信来源,select * from nls_database_parameters where parameter = 'nls_characterset' 必须先跑一遍。常见结果只有两个:al32utf8 或 zhs16gbk。别信安装文档、别看工具界面右下角提示、更别凭“我装的是中文版 oracle”就默认是 gbk——实测中,大量生产库明明是 utf8 却被当成 gbk 配置,后续所有调试都白忙。
Java 应用走 JDBC(比如 ojdbc8.jar)时,NLS_LANG 环境变量完全不起作用。Oracle JDBC 驱动不读它,只认连接 URL 里的编码参数。错误写法:jdbc:oracle:thin:@localhost:1521:orcl;正确写法必须显式声明:jdbc:oracle:thin:@localhost:1521:orcl?useUnicode=true&characterEncoding=UTF-8(对应数据库为 AL32UTF8)或 ?useUnicode=true&characterEncoding=GBK(对应 ZHS16GBK)。注意:& 是 XML/HTML 转义,实际配置里要写成 &;characterEncoding 值必须与数据库字符集严格匹配,大小写敏感,utf8 和 UTF-8 在某些旧驱动版本里行为不同。
即使连接串设对了,Java 侧仍可能出问题,因为字符串从源码生成到传给 JDBC 是多层编码链:
.java 文件保存时用的是什么编码?IDE 设置里查——不是“项目编码”,是单个文件的编码,建议统一设为 UTF-8,且带 BOM(部分老 IDE 依赖 BOM 识别)-Dfile.encoding=GBK?这个会污染整个 String 构造过程,导致 "测试" 字面量在内存里就是错的字节序列VARCHAR2 还是 NVARCHAR2?前者走数据库字符集,后者走国家字符集(NLS_NCHAR_CHARACTERSET),两者可能不同,NVARCHAR2 插入中文必须用 N'中文' 语法,否则 JDBC 会按 VARCHAR2 路径处理最容易被忽略的是:Spring Boot 默认用 application.properties 读取配置,如果该文件本身是 GBK 编码,而你写了 spring.datasource.url=jdbc:oracle:thin:@...?characterEncoding=UTF-8,那么等 Spring 解析完,URL 里 UTF-8 四个字可能已变成乱码,最终传给 JDBC 的是无效参数。
Java 调用含 OUT VARCHAR2 参数的存储过程时,乱码常发生在 CallableStatement.registerOutParameter(idx, Types.VARCHAR) 这一步。JDBC 驱动会根据该类型和当前连接的 characterEncoding 决定如何解码返回值。但如果你的存储过程内部用了 UTL_HTTP 或 DBMS_OUTPUT.PUT_LINE 输出中文,而调用方没开 setDatabaseProductVersion 或没设置 oracle.jdbc.defaultNChar=true,就可能触发隐式转换。实操建议:
立即学习“Java免费学习笔记(深入)”;
SELECT ... INTO 直接查表字段OUT 参数,注册时明确指定字符集:cs.registerOutParameter(1, Types.VARCHAR, "UTF-8")(JDBC 4.2+ 支持第三参数)cs.getString(1).getBytes(StandardCharsets.UTF_8) 的十六进制,比看控制台输出更可靠真正麻烦的不是配置项写错,而是多层编码链里某一层静默降级——比如 JVM 用 GBK 解码一个本该是 UTF-8 的 byte[],不会报错,只会吐出一串问号或方块,然后你花三小时检查 Oracle 配置,其实问题在 IDE 的文件保存编码上。