データを加工して登録処理などを行う場合、OutOfMemoryになることは容易に考えられます。
今回、仕事上でそのような機会に出くわしたので、対応方法をメモしたいと思います。
前職の最後の現場でも同様の対応をした経験があったので、
あっさり対応することが出来ました。
s2daoのFetchHandlerです。
http://s2dao.seasar.org/ja/s2dao-tiger.html#FetchHandler
本来であれば、上記のように一度の30万件取得してから違う処理を行うという流れになりますが、
FetchHandlerを使用すると、
1件取得(Fetch)するたびに処理が行えるようになります。
つまり、30万件をメモリ上に持つ必要がなくなるわけです。
では使い方。
--------------------------------------------------------------------------------------------
前提条件:バージョン1.0.48以上であること。
①s2daoをダウンロードしてzipを解凍すると、s2dao, s2dao-tigerが入っているので、
s2dao-tiger/libのhsqldb.jar以外の2つのjarをクラスパスに通します。
(最初これがないのに気付かず「そんなクラスねぇよ」と怒られていました)
②FetchHandler
③DAOクラスの該当メソッドの引数の最後に②で作成したクラスを加えます。
④上記メソッドの戻り値をintにします(取得件数を返すようになります)
⑤この状態でDAOメソッドを実行すると、FetchHandlerクラスのexecuteメソッドを実行してくれます。
--------------------------------------------------------------------------------------------
では、「取得した年齢が28歳以上の場合、アラサーフラグを立ててデータを更新する」という、
全くもって今思いついた処理を、Fetchを利用しない場合、した場合で処理を書いてみようと思います。
■Fetchしない場合
List
for (AgeDto ageDto : ageDtos) {
if (ageDto.getAge() >= 28) {
ageDto.setAround30Flg(true);
// 更新
dao.updateAgeInfo(ageDto);
}
}
■Fetchする場合
●AgeHandler.java
import org.seasar.dao.tiger.FetchHandler;
public class AgeHandlerimplements FetchHandler
public boolean execute(AgeDto dto) {
if (ageDto.getAge() >= 28) {
ageDto.setAround30Flg(true);
// 更新
dao.updateAgeInfo(ageDto);
}
// Fetch処理を続ける(やめるときはfalseを返す)
return true;
}
}
●AgeDao.java
-- 中略 --
int getAge(AgeHandler handler);
●呼び出しクラス
// Handlerクラス生成
AgeHandler handler = new AgeHandler();
int executeCount = dao.getAge(handler);
といった感じになります。
ちなみにHandlerクラスのコンストラクタを用意してあげて、
引数にHandler内で保持させたい情報などを渡すと色々なことが出来ます。
今回、30万件引っ張ってきて、ファイル出力用にデータを編集して、30万件を一度にファイル出力する、
といった処理を行った際の対応だったので、
コンストラクタにはファイル出力クラスを渡してあげて、
Handlerクラス内で引き回し、1000件たまったらファイル出力する、
といった処理に変えてあげました。
2時間以上かかっていた処理が、1時間半弱まで短縮することが出来ました。
これで部長にアピールできたかなw