1

データベースから 100 万件を超えるレコードを読み取るバッチ ジョブがあり、スクロール可能な結果セットを使用してそれらのレコードにアクセスしています。今、私はその仕事を春のバッチに変換しています。この状況では、スクロール可能な結果セットは機能しません。私は試しましたが、最初のチャンクでレコードを読み取った後、結果セットが閉じ、バッチが次のステップでそれにアクセスしようとすると、「結果セットを閉じる操作はできません」という例外がスローされます。

春バッチ初心者です。スクロール可能な結果セットロジックをリーダーに実装する方法について、どなたでも助けてください。メモリ内の 1M レコードはあまり良い考えではありません。

よろしく、

4

2 に答える 2

0

すぐに使用できる JdbcPagingItemReader または JdbcCursorItemReader を使用できます。両方を試して、どちらがあなたに最も適しているかを確認してください。

実装は両方で同じになります..構成の変更のみ!!! ;-)

どちらも、すべてをメモリに入れることなく、非常に多数のレコードを読み取ることができます。

1M レコードは Spring Batch では何もありません...適切なリーダーを使用すれば ;-)

編集:あなたのコメントに基づいて:

既存のインターフェース/実装のコード例を提供できますか?

通常、既存のサービス・Daoを利用したい場合は、ItemReaderAdapterを利用できます。これにより、read() をデリゲートするオブジェクトとメソッドを定義できます。しかし、すぐに使用できる実装は非常に基本的なものであり、起動時にカスタムの service.find() を呼び出します (InitializingBean)。したがって、メモリ内のリストに 1M オブジェクトが作成されます。

find メソッドはおそらくクエリを実行し、resultSet を List にマップするため

SQL を実装クラスから JdbcCursorItemreader に移動し、stepListener を使用して jobParameters を確認し、JdbcCursorItemreader 内に適切な Sql を設定することをお勧めします。

よろしく

于 2013-04-24T21:03:03.670 に答える
0

考えられる解決策の 1 つは、ContinuableTasklet を確認することです。タスクレットは、Spring Batch によって管理されるように「ループ」できますResultSet.next()。これにより、フレームワークがストリームを閉じることなく、1 回のアクセスでレコードを取得して処理することができます。

package de.incompleteco.spring.batch.step.tasklet;

import java.sql.ResultSet;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class ScrollableResultsetTasklet implements Tasklet {

    private boolean open = false;

    @Resource
    private DataSource dataSource;

    private String sql = "select * from test_table";

    private ResultSet rs;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        if (!open) {
            //open the resultset
            rs = open();
            open = true;//set to open
        }//end if
        //move
        rs.next();
        if (!rs.isAfterLast()) {
            //show
            System.out.println(rs.getInt(1));
            return RepeatStatus.CONTINUABLE;
        }//end if
        //done
        return RepeatStatus.FINISHED;
    }

    protected ResultSet open() throws SQLException {
        return dataSource.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY).executeQuery(sql);
    }


}

もちろん、これは「再起動可能」ではありませんが、スクロール可能な結果セットでもありません(追加の作業は必要ありません)。

チャンクから読み取る場合は、バッチ チャンク間で独自の「状態」を維持する別の pogo に結果セット マネージャーを「外部化」することを検討できます。これは次のようになります。

package de.incompleteco.spring.batch.service;

import java.sql.ResultSet;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.sql.DataSource;

public class ScrollableResultSetService {

    private boolean open = false;

    @Resource
    private DataSource dataSource;

    private String sql = "select * from test_table";

    private ResultSet rs;

    /**
     * retrieve the result set in a 'next' state
     * @return
     * @throws SQLException
     */
    public ResultSet getNext() throws SQLException {
        if (rs == null || !open) {
            //open the resulset
            rs =  dataSource.getConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY).executeQuery(sql);
        }//end if
        //move
        rs.next();
        //test
        if (rs.isAfterLast()) {
            return null;
        }//end if
        return rs;
    }

}

itemreader は次のようになります。

package de.incompleteco.spring.batch.step.item;

import java.sql.ResultSet;

import javax.annotation.Resource;

import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;

import de.incompleteco.spring.batch.service.ScrollableResultSetService;

public class ScrollableResultSetItemReader implements ItemReader<T> {

    @Resource
    private ScrollableResultSetService service;

    @Override
    public T read() throws Exception, UnexpectedInputException, ParseException,NonTransientResourceException {
        ResultSet rs = service.getNext();
        if (rs == null) {
            return null;//don't continue
        }//end if
        //process the result set into your object
        //...
        //return object 
        return T;
    }

}
于 2013-04-23T13:37:26.690 に答える