【问题标题】:Oracle JDBC Thin driver : encoding issuesOracle JDBC Thin 驱动程序:编码问题
【发布时间】:2021-09-27 22:16:57
【问题描述】:

我正在尝试从 Oracle DB 中声明的虚拟函数中检索一些数据。

函数在 SQL Developer 中是这样创建的:

create or replace NONEDITIONABLE FUNCTION hello
RETURN varchar2 is
BEGIN
  return 'Voici les caractères accentués : àéôï etc...' || chr(10) || 'ça marche ?';
END;

我的 Java 应用程序目前在 NetBeans 中执行,如下所示:

try(Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:OraDoc", "sys as sysdba", "MyPasswd123")) {
    CallableStatement cs = connection.prepareCall("{? = call hello}");
    cs.registerOutParameter(1, Types.NVARCHAR);

    cs.execute();

    byte[] bytes = cs.getBytes(1);

    logger.info(Hex.encodeHexString(bytes));

    logger.info(new String(bytes, StandardCharsets.UTF_8));
    logger.info(new String(bytes, StandardCharsets.UTF_16));
    logger.info(new String(bytes, StandardCharsets.ISO_8859_1));
    logger.info(new String(bytes, StandardCharsets.US_ASCII));
} catch(SQLException e) {
    logger.error(e.getMessage(), e);
    return;
}

输出如下:

2021-07-20 13:24:36 INFO Main:119 - 0056006f0069006300690020006c00650073002000630061007200610063007400e800720065007300200061006300630065006e0074007500e900730020003a002000e000e900f400ef0020006500740063002e002e002e000a00e700610020006d006100720063006800650020003f
2021-07-20 13:24:36 INFO Main:121 - Voici les caract?res accentu?s : ???? etc...
?a marche ?
2021-07-20 13:24:36 INFO Main:122 - Voici les caract?res accentu?s : ???? etc...
?a marche ?
2021-07-20 13:24:36 INFO Main:123 - Voici les caract?res accentu?s : ???? etc...
?a marche ?
2021-07-20 13:24:36 INFO Main:124 - Voici les caract?res accentu?s : ???? etc...
?a ma

使用相同的连接,我运行了两个不同的查询来尝试理解这个问题:

SELECT * FROM v$nls_parameters WHERE parameter LIKE '%CHARACTERSET';
SELECT * FROM nls_session_parameters;

产生以下(截断):

2021-07-20 13:24:36 INFO Main:51 - PARAMETER -> NLS_CHARACTERSET
2021-07-20 13:24:36 INFO Main:51 - VALUE -> AL32UTF8
2021-07-20 13:24:36 INFO Main:51 - CON_ID -> 0
2021-07-20 13:24:36 INFO Main:51 - PARAMETER -> NLS_NCHAR_CHARACTERSET
2021-07-20 13:24:36 INFO Main:51 - VALUE -> AL16UTF16
2021-07-20 13:24:36 INFO Main:51 - CON_ID -> 0
2021-07-20 13:24:36 INFO Main:55 - ==============================================================
2021-07-20 13:24:36 INFO Main:63 - PARAMETER -> NLS_LANGUAGE
2021-07-20 13:24:36 INFO Main:63 - VALUE -> AMERICAN
2021-07-20 13:24:36 INFO Main:63 - PARAMETER -> NLS_TERRITORY
2021-07-20 13:24:36 INFO Main:63 - VALUE -> AMERICA

我尝试了不同的方法,例如:

  • 在连接字符串的末尾添加“?useUnicode=true&characterEncoding=utf-8”,就像我连接 MySQL 数据库时所做的那样
  • 根据How to setup the NLS_LANG Properly for UNIX 将 NLS_LANG 更改为 NLS_LANG=AMERICAN_AMERICA.UTF8
  • 注册 outParameter 时使用 NVARCHAR 而不是 VARCHAR
  • 添加参数-Doracle.jdbc.defaultNChar=true

但它并没有改善。

作为参考,这是我在那个项目中仅有的两个依赖项(与 Oracle 相关):

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc11</artifactId>
    <version>21.1.0.0</version>
</dependency>
<dependency>
    <groupId>com.oracle.ojdbc</groupId>
    <artifactId>orai18n</artifactId>
    <version>19.3.0.0</version>
</dependency>
  • 我已删除 NLS_LANG 环境变量(感谢 @Wernfried Domscheit)
  • 注册 out 参数 a 时,我已切换回 VARCHAR 而不是 NVARCHAR
  • 我正在使用 getString()(我正在使用 getBytes() 来尝试查看我是否接收到 ? 字符或者是否是显示问题。
  • 我尝试使用 UTF_16BE 字符集创建字符串

结果还是一样:

try(Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:OraDoc?useUnicode=true&characterEncoding=utf-8", "sys as sysdba", "MyPasswd123")) {
    CallableStatement cs = connection.prepareCall("{? = call hello}");
    cs.registerOutParameter(1, Types.VARCHAR);

    cs.execute();

    logger.info(cs.getString(1));
} catch(SQLException e) {
    logger.error(e.getMessage(), e);
    return;
}
2021-07-20 17:00:20 INFO Main:43 - Voici les caract?res accentu?s : ???? etc...

我错过了什么?

【问题讨论】:

  • 您是否尝试过使用getStringgetNString
  • Java 不使用您客户端的NLS_LANG 设置,请参阅Database JDBC Developer's Guide - Globalization Support
  • 使用 Types.VARCHAR 代替 Types.NVARCHAR 和 getString 代替 getBytes。如果您使用 getBytes,请尝试使用 UTF-16BE 进行编码。
  • 你的控制台支持 unicode 吗?
  • @SayanMalakshinov 天哪,我现在很生气。这实际上是我测试的第一件事,但显然不正确......事实证明,直接在我的 bash konsole 中运行 java 应用程序非常有效。

标签: java oracle jdbc ojdbc


【解决方案1】:

首先,您的函数定义为RETURN varchar2,而不是nvarchar2,但您在这里使用的是cs.registerOutParameter(1, Types.NVARCHAR);。并且不要对字符串使用cs.getBytes(1),而是使用getString()

【讨论】:

  • 谢谢!我已根据您的回复编辑了我的问题。
【解决方案2】:

感谢@SayanMalakshinov,我意识到这是 netbeans 的错误配置。

我在项目的 nbactions.xml 文件部分添加了&lt;Env.JAVA_TOOL_OPTIONS&gt;-Dfile.encoding=UTF8&lt;/Env.JAVA_TOOL_OPTIONS&gt;,它立即起作用了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-15
    • 2012-10-05
    • 2013-08-16
    • 2010-10-05
    • 2012-03-10
    • 2011-06-08
    • 1970-01-01
    相关资源
    最近更新 更多