乱码出在JDBC连接层与JVM编码协商环节,需升级ojdbc8+驱动、JVM加-Dfile.encoding=UTF-8和-Doracle.jdbc.defaultNChar=true,禁用URL中characterEncoding等MySQL参数,并通过DUMP验证UTF-8字节流。

Java查Oracle中文显示为?或方块,但数据库确认存的是AL32UTF8且数据本身没问题——这基本可以断定:乱码出在JDBC连接层与JVM编码协商环节,不是数据库或数据问题。
确认数据库实际字符集,别信“默认”或“安装界面”
第一件事不是改代码,而是执行SQL确认服务端真实字符集:
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');只认这两列的值:AL32UTF8(推荐)或ZHS16GBK。如果返回US7ASCII或WE8ISO8859P1,说明数据库根本不支持中文存储,所有后续配置都白搭。
- 不要依赖
SELECT USERENV('LANGUAGE') FROM DUAL,它返回的是会话级NLS设置,不是数据库字符集 - 不要凭“我装的是中文版Oracle”就假设是GBK——实测大量生产库是
AL32UTF8却按GBK配URL,越调越错 - 如果查出来是
ZHS16GBK,后面所有配置必须严格匹配GBK,大小写敏感,gbk和GBK在某些驱动版本里行为不同
ojdbc8+驱动 + 干净URL + JVM强制UTF-8
旧驱动(如ojdbc6)对AL32UTF8传输支持不完整:getString()可能静默截断,setCharacterStream()可能转义错误;而URL里加characterEncoding=utf8这种MySQL风格参数,Oracle JDBC完全不识别,加了不仅无效,还可能触发WARN日志干扰排查。
立即学习“Java免费学习笔记(深入)”;
- 必须用
com.oracle.database.jdbc:ojdbc8(Oracle 12c+)或ojdbc11(21c+),Maven坐标别用过时的oracle.jdbc:ojdbc6 - JDBC URL中**不要出现**
characterEncoding、useUnicode、encoding等参数——它们是MySQL专属,Oracle驱动直接忽略 - 推荐URL格式:
jdbc:oracle:thin:@//host:port/service_name,干净无冗余参数 - JVM启动必须加
-Dfile.encoding=UTF-8,否则String.getBytes()、new String(byte[])等操作全按错编码执行 - 必须加
-Doracle.jdbc.defaultNChar=true,它让驱动对VARCHAR2列也启用Unicode语义读写,绕过NLS_LANG干扰
连接池初始化SQL防NLS污染
即使URL干净、JVM编码正确,连接池(如HikariCP)复用连接时,上一个会话可能残留NLS_LANGUAGE='SIMPLIFIED CHINESE'这类设置,导致当前查询被错误解释。
- 在连接池配置中显式设
connectionInitSql=ALTER SESSION SET NLS_LANGUAGE='AMERICAN' NLS_TERRITORY='AMERICA' - 这条SQL在每次连接获取时执行,确保会话级NLS不干扰字符解码逻辑
- 别指望
NLS_LANG环境变量——JDBC驱动不读它,设了也白设
验证字节流是否真走UTF-8,别只看“看起来正常”
光看SELECT name FROM user WHERE id = 1返回是不是中文,容易误判——因为某些场景下“看起来正常”只是巧合(比如字段值恰好能被当前错误编码映射成可显字符)。
- 在数据库侧运行:
SELECT DUMP('你好', 1016) FROM DUAL,正确结果应为TYP=1 LEN=6: 60,0,4f,60,0,4f(UTF-8十六进制) - 在Java里用
rs.getBytes("name")拿到原始字节数组,打印其十六进制(如Arrays.toString(bytes)),对比是否与上面一致;若不一致,说明驱动在传输中做了隐式转换 - 运行时打印
System.getProperty("file.encoding"),必须是UTF-8;再确认System.getProperty("oracle.jdbc.defaultNChar")返回true
最容易被忽略的是Spring Boot的application.properties文件本身编码——如果该文件是GBK保存的,而你写了spring.datasource.url=jdbc:oracle:thin:@?characterEncoding=UTF-8,Spring解析完,URL里的UTF-8四个字可能已变成乱码字节。


















