ojdbc7/ojdbc8 中的字符集问题与 ojdbc6 中的正确行为
Charset issues in ojdbc7/ojdbc8 vs. correct behaviour in ojdbc6
我们有一个具有以下字符集设置的 Oracle 数据库
SELECT parameter, value FROM nls_database_parameters WHERE parameter like 'NLS%CHARACTERSET'
NLS_NCHAR_CHARACTERSET: AL16UTF16
NLS_CHARACTERSET: WE8ISO8859P15
在这个数据库中,我们有一个带有 CLOB
字段的 table,它有一条以以下字符串开头的记录,显然存储在 ISO-8859-15 中:X²ARB
(此处正确转换为 unicode,特别是 2-上标很重要且正确)。
然后我们有以下简单的代码来获取值,它应该通过 Oracle 中的全球化支持自动将字符集转换为 unicode:
private static final String STATEMENT = "SELECT data FROM datatable d WHERE d.id=2562456";
public static void main(String[] args) throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
try (Connection conn = DriverManager.getConnection(DB_URL);
ResultSet rs = conn.createStatement().executeQuery(STATEMENT))
{
if (rs.next()) {
System.out.println(rs.getString(1).substring(0, 5));
}
}
}
运行 代码打印:
- 与
ojdbc8.jar
和 orai18n.jar
:X�ARB
-- 不正确
- 与
ojdbc7.jar
和 orai18n.jar
:X�ARB
-- 不正确
- 与
ojdbc-6.jar
: X²ARB
-- 正确
通过使用 UNISTR
并将语句更改为 SELECT UNISTR(data) FROM datatable d WHERE d.id=2562456
我可以将 ojdbc7.jar
和 ojdbc8.jar
变为 return 正确的值,但这需要对代码进行了未知数量的更改,因为这可能不是唯一出现问题的地方。
我可以对客户端或服务器配置做些什么来使 所有 查询 return 正确编码的值而无需修改语句吗?
请看Database JDBC Developer's Guide - Globalization Support
The basic Java Archive (JAR) file ojdbc7.jar, contains all the
necessary classes to provide complete globalization support for:
CHAR
or VARCHAR
data members of object and collection for the character sets US7ASCII
, WE8DEC
, WE8ISO8859P1
, WE8MSWIN1252
, and UTF8
.
To use any other character sets in CHAR
or VARCHAR
data members of
objects or collections, you must include orai18n.jar in the CLASSPATH
environment variable:
ORACLE_HOME/jlib/orai18n.jar
看起来确实像是 JDBC thin 驱动程序中的错误(我假设您使用的是 thin)。它可能与 LOB 预取有关,其中 CLOB 的长度、字符集 ID 和 LOB 数据的第一部分在带内发送。此功能是在 11.2 中引入的。作为解决方法,您可以通过设置连接 属性
来禁用 lob 预取
oracle.jdbc.defaultLobPrefetchSize
到“-1”。同时我会跟进这个错误以确保它得到修复。
我们有一个具有以下字符集设置的 Oracle 数据库
SELECT parameter, value FROM nls_database_parameters WHERE parameter like 'NLS%CHARACTERSET'
NLS_NCHAR_CHARACTERSET: AL16UTF16
NLS_CHARACTERSET: WE8ISO8859P15
在这个数据库中,我们有一个带有 CLOB
字段的 table,它有一条以以下字符串开头的记录,显然存储在 ISO-8859-15 中:X²ARB
(此处正确转换为 unicode,特别是 2-上标很重要且正确)。
然后我们有以下简单的代码来获取值,它应该通过 Oracle 中的全球化支持自动将字符集转换为 unicode:
private static final String STATEMENT = "SELECT data FROM datatable d WHERE d.id=2562456";
public static void main(String[] args) throws Exception {
Class.forName("oracle.jdbc.driver.OracleDriver");
try (Connection conn = DriverManager.getConnection(DB_URL);
ResultSet rs = conn.createStatement().executeQuery(STATEMENT))
{
if (rs.next()) {
System.out.println(rs.getString(1).substring(0, 5));
}
}
}
运行 代码打印:
- 与
ojdbc8.jar
和orai18n.jar
:X�ARB
-- 不正确 - 与
ojdbc7.jar
和orai18n.jar
:X�ARB
-- 不正确 - 与
ojdbc-6.jar
:X²ARB
-- 正确
通过使用 UNISTR
并将语句更改为 SELECT UNISTR(data) FROM datatable d WHERE d.id=2562456
我可以将 ojdbc7.jar
和 ojdbc8.jar
变为 return 正确的值,但这需要对代码进行了未知数量的更改,因为这可能不是唯一出现问题的地方。
我可以对客户端或服务器配置做些什么来使 所有 查询 return 正确编码的值而无需修改语句吗?
请看Database JDBC Developer's Guide - Globalization Support
The basic Java Archive (JAR) file ojdbc7.jar, contains all the necessary classes to provide complete globalization support for:
CHAR
orVARCHAR
data members of object and collection for the character setsUS7ASCII
,WE8DEC
,WE8ISO8859P1
,WE8MSWIN1252
, andUTF8
.To use any other character sets in
CHAR
orVARCHAR
data members of objects or collections, you must include orai18n.jar in theCLASSPATH
environment variable:
ORACLE_HOME/jlib/orai18n.jar
看起来确实像是 JDBC thin 驱动程序中的错误(我假设您使用的是 thin)。它可能与 LOB 预取有关,其中 CLOB 的长度、字符集 ID 和 LOB 数据的第一部分在带内发送。此功能是在 11.2 中引入的。作为解决方法,您可以通过设置连接 属性
来禁用 lob 预取oracle.jdbc.defaultLobPrefetchSize
到“-1”。同时我会跟进这个错误以确保它得到修复。