【问题标题】:Oracle database response in Quarkus returns string of numbersQuarkus 中的 Oracle 数据库响应返回数字字符串
【发布时间】:2021-11-30 19:11:12
【问题描述】:

在我开始之前,我必须说这是一个工作项目,我不能分享所有细节。在不破坏 NDA 的情况下,我会尽可能多地包括在内。感谢您的理解。

我正在开发与 Oracle 数据库通信的 Quarkus (2.3.0) 应用程序。在其中,我执行了一个存储过程,并且应该得到一个字符串作为响应。

经过一番摆弄,我能够连接到数据库并执行存储过程。但是,响应似乎以某种使用截断的 ascii 编码(丢弃前导零)的方式编码。

606578838769828362103232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232326065788783698295838465848583627975604765788783698295838465848583621032323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323260657883876982839583698462103232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323260657883876982476210323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232604765788387698283958369846210323232323232323232323232323232323232323232323232323232323232323232323232323232323232323260476578838769828362 P>

起初,我假设每个字符代码都是两个数字长。但是,其他响应也包含字符代码大于 100 的字母。

使用2字符代码的假设,我可以解析上面的响应:

<ANSWERS>
                                                <ANWSER_STATUS>OK</ANWSER_STATUS>
                                                <ANSWERS_SET>
                                                    <ANSWER/>
                                                </ANSWERS_SET>
                                            </ANSWERS>

经过询问,数据库管理员告诉我数据库使用WE8ISO8859P15编码。

问题

如何让 Quarkus 正确理解 WE8ISO8859P15 编码,以便下面代码中的 resultString 包含响应 XML 而不是一串数字?

代码

application.properties

quarkus.datasource.db-kind=oracle
quarkus.datasource.username=${DB_USERNAME:username}
quarkus.datasource.password=${DB_PASSWORD:password}
quarkus.datasource.jdbc.url=jdbc:oracle:thin:@//${DB_HOST:dbhost}:${DB_PORT:1521}/${DB_NAME:dbname}

DatabaseCommunicator.java

@Singleton
public class DatabaseCommunicator {

    @Inject
    AgroalDataSource dataSource;

    private static final String QUERY = "{ ? = call abc.SOME_WORDS.STORED_PROCEDURE_NAME(?) }";
    
    public Object getDetails(String objectId) {
        String resultString;

        try (Connection connection = dataSource.getConnection(); CallableStatement statement = connection.prepareCall(QUERY)) {
            String queryBody = "<objectId>" + objectId + "</objectId>";

            statement.setString(2, queryBody);
            statement.registerOutParameter(1, Types.CLOB);

            statement.execute();

            Clob resultClob = statement.getClob(1);
            resultString = readClob(resultClob); // Value of this String is the long number string.
        } catch (SQLException | IOException ex) {
            throw new DatabaseException("Exception while communicating with database", ex);
        }

        return resultString;
    }

    private String readClob(Clob input) throws IOException, SQLException {
        InputStream stream = input.getAsciiStream();

        StringBuilder buffer = new StringBuilder();
        int character = stream.read();

        while (character != -1) {
            buffer.append(character);
            character = stream.read();
        }

        return buffer.toString();
    }
}

pom.xml

[...]
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-agroal</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-jdbc-oracle</artifactId>
    </dependency>
    <dependency>
      <groupId>com.oracle.database.nls</groupId>
      <artifactId>orai18n</artifactId>
    </dependency>
    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc11</artifactId>
    </dependency>
[...]

【问题讨论】:

  • 应该能够从 'iso-8859-15' 解码到 'utf8'
  • 我在readClob() 的第一条语句下方添加了InputStreamReader reader = new InputStreamReader(stream, Charset.forName("ISO-8859-15"));,然后用它代替stream 进行阅读。但是,恐怕这仍然会产生相同的数字字符串。
  • 我想知道是否可以为 iso-8858-15 使用 ascii 流? InputStream stream = input.getAsciiStream();如果您知道如何解决此问题,请回答,因为我认为这对其他人有用。
  • 还有一个getCharacterStream(); 方法可以返回相同的数字字符串。我找不到任何其他返回数据的方法。

标签: java oracle jdbc quarkus


【解决方案1】:

我曾期望 JDBC 驱动程序自动解码来自数据库的响应。然而,事实证明这并没有发生。

相反,我在 JDBC 驱动程序中找到了帮助我自己解码的相关代码。为此,我使用了作为 Quarkus BOM 一部分的 quarkus-jdbc-oracle 依赖项:

    <dependency>
      <groupId>com.oracle.database.jdbc</groupId>
      <artifactId>ojdbc11</artifactId>
    </dependency>

然后,我使用驱动程序中已经存在的内置解码逻辑将数字字符串转换为我可以使用的东西:

import static oracle.sql.CharacterSet.WE8ISO8859P15_CHARSET;

import oracle.sql.converter.CharacterConverterFactoryJDBC;
import oracle.sql.converter.JdbcCharacterConverters;


class Example {
    private String readClob(Clob input) throws IOException, SQLException {
        InputStream stream = input.getAsciiStream();

        CharacterConverterFactoryJDBC converter = new CharacterConverterFactoryJDBC();
        JdbcCharacterConverters converters = converter.make(WE8ISO8859P15_CHARSET);

        byte[] bytes = stream.readAllBytes();
        return converters.toUnicodeString(bytes, 0, bytes.length);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2020-07-07
    • 2020-03-23
    • 2013-10-02
    • 2013-12-13
    相关资源
    最近更新 更多