1

MySQLデータベースに接続するTomcat6で実行されているJavaプロジェクトに取り組んでいます。お客様のサーバーでのテストとしてローカルでテストする場合は、すべての手順が正常に実行されます。ただし、例外が1つあります。これは、レポートを生成するために大量のデータを取得する1つのプロシージャの場合です。MySQLから実行する場合、ストアドプロシージャは13分ほどかかります。アプリケーションをローカルで実行してオンラインデータベースに接続すると、手順は機能しますが、機能しないのは、クライアントのサーバーで実行した場合のみです。

クライアントはサーバーをかなり保護しているため、サーバーの制御は制限されていますが、問題の解決を求めています。ログファイルを確認すると、ストアドプロシージャを実行する関数からエラーがスローされることはありません。そして、コードにいくつかのデバッグログを入れると、execute呼び出しに到達することを示していますが、呼び出しの直後にデバッグをログに記録せず、catchにエラーを記録せず、finallyセクションに入ります。

彼らは、MySQLログにタイムアウトエラーがないと主張しています。

何がこの問題を引き起こす可能性があるかについて誰かが何か考えを持っているなら、どんな助けでもありがたいです。

更新

サーバー管理者に少し話しかけた後、私はついにカタリナログにアクセスできるようになりました。それらのログで、私はついに何らかの意味を持つエラーを見つけました。

Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2894)
        at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:117)
        at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:407)
        at java.lang.StringBuffer.append(StringBuffer.java:241)
        at be.playlane.mink.database.SelectExportDataProcedure.bufferField(SelectExportDataProcedure.java:68)
        at be.playlane.mink.database.SelectExportDataProcedure.extractData(SelectExportDataProcedure.java:54)
        at org.springframework.jdbc.core.JdbcTemplate.processResultSet(JdbcTemplate.java:1033)
        at org.springframework.jdbc.core.JdbcTemplate.extractReturnedResultSets(JdbcTemplate.java:947)
        at org.springframework.jdbc.core.JdbcTemplate$5.doInCallableStatement(JdbcTemplate.java:918)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:876)
        at org.springframework.jdbc.core.JdbcTemplate.call(JdbcTemplate.java:908)
        at org.springframework.jdbc.object.StoredProcedure.execute(StoredProcedure.java:113)
        at be.playlane.mink.database.SelectExportDataProcedure.execute(SelectExportDataProcedure.java:29)
        at be.playlane.mink.service.impl.DefaultExportService$ExportDataRunnable.run(DefaultExportService.java:82)
        at java.lang.Thread.run(Thread.java:636)

これがアプリケーションログに記録されないのは奇妙なことですが、trycatchにラップされている場合でも同様です。エラーに基づくと、問題はこのメソッドにあります。

public Object extractData(ResultSet rs) throws SQLException, DataAccessException
  {
    StringBuffer buffer = new StringBuffer();

    try
    {
      // get result set meta data
      ResultSetMetaData meta = rs.getMetaData();
      int count = meta.getColumnCount();

      // get the column names; column indices start from 1
      for (int i = 1; i < count + 1; ++i)
      {

        String name = meta.getColumnName(i);
        bufferField(name, i == count, buffer);
      }

      while (rs.next())
      {

        // get the column values; column indices start from 1
        for (int i = 1; i < count + 1; ++i)
        {
          String value = rs.getString(i);
          bufferField(value, i == count, buffer);
        }
      }
    }
    catch (Exception e)
    {
      logger.error("Failed to extractData SelectExportDataProcedue: ", e);
    }

    return buffer.toString();
  }

  private void bufferField(String field, boolean last, StringBuffer buffer)
  {
    try
    {
      if (field != null)
      {

        field = field.replace('\r', ' ');
        field = field.replace('\n', ' ');

        buffer.append(field);
      }

      if (last)
      {
        buffer.append('\n');
      }
      else
      {
        buffer.append('\t');
      }
    }
    catch (Exception e)
    {
      logger.error("Failed to bufferField SelectExportDataProcedue: ", e);
    }
  }

これらの機能の目的は、特定の結果セットをExcelファイルにエクスポートすることです(これはより高いレベルで発生します)。

したがって、これを最適化するためのヒントがあれば、大歓迎です。

4

1 に答える 1

2

わかりました、あなたのスタックトレースはあなたに答えを与えます:

Exception in thread "Thread-16" java.lang.OutOfMemoryError: Java heap space

これが、ログに記録していない理由です。アプリケーションがクラッシュしています(具体的にはスレッド)。説明から判断すると、ページングする必要のある大規模なデータセットがあるようです。

      while (rs.next())
      {

        // get the column values; column indices start from 1
        for (int i = 1; i < count + 1; ++i)
        {
          String value = rs.getString(i);
          bufferField(value, i == count, buffer);
        }
      }

これはあなたがスレッドダイであるところです(おそらく)。基本的に、StringBufferはメモリを使い果たします。それを修正することに関しては、膨大な量のオプションがあります。クライアント側の問題でより多くのメモリをスローします(JVMを構成することによって(ここにリンクがあります): JVMの最大メモリ使用量を設定するにはどうすればよいですか?

または、すでにそれを行っている場合は、より多くのRAMをデバイスに投入します。

プログラミングの観点からは、これはレポートの地獄のように聞こえます。(可能であれば)バッファリングするのではなく、MySQLにクランチする数値の一部をオフロードすることもできます。または、これが巨大なレポートである場合は、ファイルにストリーミングしてから、バッファリングされたストリームを介してレポートを読み取ることを検討します。

それは完全にレポートが何であるかに依存します。小さい場合は、結果セットを最小化するためにSQLでより多くの作業を行うことを目指します。それが巨大なレポートである場合、バッファリングは他のオプションです。

欠落している可能性のあるもう1つの可能性は、ResultSet(実装によって異なります)がおそらくバッファリングされていることです。つまり、すべてを文字列に読み込む代わりに、レポートでResultSetオブジェクトを直接取得して、そこから出力できる可能性があります。もちろん、これの欠点は、漂遊SQL例外がレポートを強制終了することです。

幸運なことに、私は最初にメモリオプションを試してみます。あなたは128のような陽気に小さいもので走っているかもしれません、そしてそれは単純でしょう(私はこれが遠隔管理されたマシンでたくさん起こるのを見ました)。

于 2012-07-30T15:50:59.443 に答える