9

UTF-16 でエンコードされた文字列を AL32UTF8 Oracle データベースに格納しようとしています。

私たちのプログラムは、文字セットとして使用するデータベースで完全に動作しますWE8MSWIN1252。それを使用するデータベースで実行しようとするとAL32UTF8java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column.

以下のテストケースでは、入力データが長くなりすぎない限り、すべて正常に動作します。

入力文字列は 4000 文字を超えることができます。入力を遮断する必要があることはわかっていますが、できるだけ多くの情報を保持したいと考えています。

データベース テーブルは、CHARキーワードを使用して定義されます (以下を参照)。これにより、任意の文字セットの最大 4000 文字を保存できるようになることを期待していました。これはできますか?もしそうなら、どのように?

StringUTF8を a を使用するように変換しようとしましたが、ByteBuffer成功しませんでした。OraclePreparedStatement.setFormOfUse(...)また、私たちを助けませんでした。

a への切り替えCLOBはオプションではありません。紐が長すぎる場合はカットが必要です。

これは現時点でのコードです。

public static void main(String[] args) throws Exception {
    String ip ="193.53.40.229";
    int port = 1521;
    String sid = "ora11";
    String username = "obasi";
    String password = "********";

    String driver = "oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@" + ip + ":" + port + ":" + sid;
    Class.forName(driver);

    String shortData = "";
    String longData = "";
    String data;

    for (int i = 0; i < 5; i++)
        shortData += "é";

    for (int i = 0; i < 4000; i++)
        longData += "é";

    Connection conn = DriverManager.getConnection(url, username, password);

    PreparedStatement stat = null;
    try  {
        stat = conn.prepareStatement("insert into test_table_short values (?)");
        data = shortData.substring(0, Math.min(5, shortData.length()));
        stat.setString(1, data);
        stat.execute();

        stat = conn.prepareStatement("insert into test_table_long values (?)");
        data = longData.substring(0, Math.min(4000, longData.length()));
        stat.setString(1, data);
        stat.execute();
    } finally {
        try {
            stat.close();
        } catch (Exception ex){}
    }
}

これは単純なテーブルの作成スクリプトです。

CREATE TABLE test_table_short (
    DATA    VARCHAR2(5 CHAR);
);

CREATE TABLE test_table_long (
    DATA    VARCHAR2(4000 CHAR);
);

テストケースは短いデータで完全に機能します。ただし、長いデータではエラーが発生し続けます。longData3000 文字しかない場合でも、正常に実行されません。

前もって感謝します!

4

2 に答える 2

10

Oracle 12.1 より前では、VARCHAR2列が宣言されていても、データベース文字セットで 4000 バイトのデータを格納できる列に制限されていましたVARCHAR2(4000 CHAR)。文字列のすべての文字は、UTF-8 文字セットで 2 バイトのストレージを必要とするため、列に 2000 文字を超える文字を格納することはできません。もちろん、一部の文字が実際に 1 バイトのストレージしか必要としない場合や、一部の文字が 2 バイトを超えるストレージを必要とする場合、その数は変わります。データベースの文字セットが Windows-1252 の場合、文字列のすべての文字に必要なストレージは 1 バイトだけなので、列に 4000 文字を格納できます。

文字列が長いので、列をCLOBではなくとして宣言することは可能でしょうVARCHAR2か? これにより、(効果的に) 長さの制限が取り除かれます ( CLOBOracle のバージョンとブロック サイズに応じて a のサイズに制限がありますが、少なくとも数 GB の範囲内です)。

Oracle 12.1 以降を使用している場合、このmax_string_sizeパラメーターを使用すると、列の最大サイズをVARCHAR24000 バイトから 32767 バイトに増やすことができます。

于 2012-07-19T14:32:20.087 に答える
4

文字列を必要なバイト長にカットすることで、この問題を解決しました。これは単に使用するだけでは実行できないことに注意してください

stat.substring(0, length)

これにより、許可されているよりも最大 3 倍長くなる可能性がある UTF-8 文字列が生成されるためです。

while (stat.getBytes("UTF8").length > length) {
  stat = stat.substring(0, stat.length()-1);
}

これは設定された「file.encoding」に依存し、Windows-1252 または UTF-8 バイトを生成するため、stat.getBytes() を使用しないでください。

Hibernate を使用している場合は、org.hibernate.Interceptor を使用してこれを行うことができます!

于 2013-03-15T10:02:32.233 に答える