CLOB

2012-03-19 8 views
3

"リモート" H2データベース(実際にはローカル・ドライブにありますが、tcpを使用してアクセスします)の表から1つのテキスト列(CLOB)を取り出し、最初の100プログラムは、結果セットの次の行を検索する際にハングします。一方、組み込みデータベースと同じデータベースにアクセスする場合は問題ありません。私は、サーバー(つまりTCP)メソッドを使用してデータベースにアクセスするH2のコンソールアプリケーションを使用して、テーブルの行を表示しようとすると、私は、次のエラーメッセージが表示されます。CLOB

IO Exception: "java.io.IOException: org.h2.message.DbException: The object is already closed [90007-164]"; 
"lob: null table: 14 id: 1" [90031-164] 90031/90031 

ここでプログラムです。システムプロパティを設定する呼び出しのコメントを外すと、プログラムが機能します。私はまた、文字ストリームを使用して列を取得しようとしました。または単に定数USE_STREAMによって制御されるgetStringを呼び出しました。ここで

import java.sql.*; 
import java.util.*; 
import java.io.*; 

public class Jdbc4 
{ 
    private static final boolean USE_STREAM = false; 

    public static void main(String[] args) throws Exception 
    { 
     //System.setProperty("h2.serverResultSetFetchSize", "50"); 
     Connection conn = null; 
     try { 
      Class.forName("org.h2.Driver").newInstance(); 
      conn = DriverManager.getConnection("jdbc:h2:tcp://localhost/file:C:/h2/db/test/test;IFEXISTS=TRUE", "sa", ""); 
      Statement stmt = conn.createStatement(); 
      String sql = "select select_variables from ipm_queues"; 
      ResultSet rs = stmt.executeQuery(sql); 
      int count = 0; 
      while (rs.next()) { 
       ++count; 
       String s; 
       if (USE_STREAM) { 
        Clob clob = rs.getClob(1); 
        Reader rdr = clob.getCharacterStream(); 
        char[] cbuf = new char[1024]; 
        StringBuffer sb = new StringBuffer(); 
        int len; 
        while ((len = rdr.read(cbuf, 0, cbuf.length)) != -1) 
         sb.append(cbuf, 0, len); 
        rdr.close(); 
        s = sb.toString(); 
        clob.free(); 
       } 
       else 
        s = rs.getString(1); 
       System.out.println(count + ": " + s); 
      } 
     } 
     finally { 
      if (conn != null) 
       conn.close(); 
     } 
    } 
} 

はDDLは、(あなたはそれが最初にMySQLのテーブルだった見ることができます)テーブルを作成するためのものです::あり結果に違いはありません

CREATE TABLE `ipm_queues` (
    `oid` bigint NOT NULL, 
    `queue_id` varchar(256) NOT NULL, 
    `store_id` bigint NOT NULL, 
    `creation_time` datetime NOT NULL, 
    `status` bigint NOT NULL, 
    `deleted` bigint NOT NULL, 
    `last_mod_time` datetime NOT NULL, 
    `queue_name` varchar(128), 
    `select_variables` text, 
    `where_clause` text, 
    `from_table` varchar(128), 
    `order_by` varchar(256), 
    `from_associate_table` varchar(256), 
    `from_view` varchar(128) 
); 

ALTER TABLE ipm_queues 
    ADD CONSTRAINT ipm_queues_pkey PRIMARY KEY (oid); 

CREATE UNIQUE INDEX ipm_queues_key_idx ON ipm_queues(queue_id, store_id); 

CREATE INDEX ipm_queues_str_idx ON ipm_queues(store_id); 
+0

データを読み取るために使用したコードを投稿することはできますか? "オブジェクトはすでに閉じられています"というエラーメッセージは、予期せぬJDBC呼び出しのように聞こえます(私は間違っているとは言いませんが、予期せぬことです)。アプリケーションコードを見ることなく、どこに問題があるのか​​は分かりません。 –

+0

"オブジェクトは既に閉じられています"というエラーメッセージは、クエリを入力するとH2 Consoleアプリケーションによって生成されます。 – RonAaaronson

+0

select * from ipm_queues; (エラーメッセージは私のコードのものではありません) – RonAaaronson

答えて

0

あなたはおそらくより多くの詳細を与える必要がありますが、ネットワーク接続を確認しましたか?多量のデータを取得しようとするとすぐに、データベースサーバーが接続(またはネットワーク接続)をブロックしている可能性があります。これは「一種の」保護になる可能性があります。

+0

テーブルには523の行があります。私がシステムプロパティh2.serverResultSetFetchSizeを値600で指定してアプリケーションを起動したとき、3行だけを取得した後にハングしました!このプロパティを値1で指定すると、もはやハングしませんでした。 87までの値は正常に動作するようです。 88行が返された後に値が88になりました。 – RonAaaronson

+0

Yohann、 "自分のネットワーク接続をチェックする"という意味がわかりません。私は "localhost"に接続しています。私の "データベースサーバー"はバニラのH2インストールだけです。私はこのテーブルの523行すべてを取り出すことができるはずです。私は完全に理解していないsシステムパラメータを変更することができます。 – RonAaaronson

+0

ネットワークに問題があるわけではありません。つまり、あまりにも多くのデータを送信する必要があると考えられる場合、サーバーがjdbc接続をハングアップする可能性があります。 –

3

私はハングアップの原因を理解していると思います。私はh2.serverResultSetFetchSize値600を使用する最も単純なケースを調べました。これは、私が知っている523行よりも大きい値です。私が言及したように、私は最初の3行(単一のCLOB列)を取得することができます。次に、4行目の検索でハングアップするか、「オブジェクトが既に閉じられています」例外が発生します。

最初の3つの列を構成する実際の文字列の長さがやや短いように見え、orgH2.value.ValueLobDbクラスのgetInputStreamは既にデータを持ち、このデータで構築されたByteArrayInputStreamを返します。 4行目のデータはまだサーバー側にあるため、サーバー側のLOBからデータをフェッチするために、実際のRemoteInputStreamを構築する必要があります。

問題は次のとおりです。クラスorg.h2.server.TcpServerThreadは、SmallLRUCacheのインスタンスでこれらのLOBをキャッシュしています。このキャッシュは、最も最近参照されたLOBのみを維持するように設計されているようです。このキャッシュのデフォルトサイズはシステムプロパティh2.serverCachedObjectsによって与えられ、デフォルトは64ですが、デフォルトのフェッチサイズは100です。したがって、デフォルトのh2.serverResultSetFetchSizeプロパティをオーバーライドしていなくても、すべてのローが十分に大きければキャッシュされたLOBを必要とする列の場合、フェッチ・サイズ> 64の場合は、最初の行を表すLOBがキャッシュからフラッシュされ、最初の行を取得することさえできません。

LRUキャッシュは、アクティブな結果セット内にあるLOBを保持するために間違った構造のようです。確かに、デフォルトのフェッチサイズより小さいデフォルトのキャッシュサイズを持つことは理想的ではありません。

+0

はい、これはバグであり、H2の次のバージョンで修正する必要があります。 –

+0

H2mコンソールを使用して1.3.166で再テストしただけで、ipm_queuesから行を取得しても失敗します:SELECT * FROM IPM_QUEUES; IO例外: "java.io.IOException:org.h2.message.DbException:オブジェクトはすでに閉じられています[90007-166]"; "ロブ:ヌルテーブル:465 ID:55034" [90031-166] 90031/90031(ヘルプ)この場合、各行にCLOBである複数の列があるため、単にキャッシュのサイズを大きくしても機能しません。私はあなたがLRUキャッシュがこの機能のための正しいデータ構造ではない可能性があることに気づかなければならないと思います。 – RonAaaronson

+0

あなたが正しいです、それはすべての場合に動作しません。より良い解決策が良いでしょう。パッチは歓迎します:-) –