RowHandlerを使ったCSV出力
RowHandlerは1行分の検索結果を扱うためのインターフェースです。このインターフェースを実装することで、検索結果から任意の処理を行うことができます。
大量の検索結果をCSVデータとして出力することを考えてみます。iBATISは検索結果をListデータとして返してくれます。例えば1千万件もあるデータをqueryForList
で取得すると、1千万件もの検索結果を保持するListがJavaのオブジェクトして生成されてしまいます。このListを全件走査してCSVファイルを出力した場合、Listは単なる中間データとして存在するだけです。一時的とはいえ大量のメモリを消費してしまうことが予想されます。
このようなケースでは、RowHandlerを使って大量データを1件ずつCSVファイルに出力すると効果的です。DEPT表の全件をCSV出力してみます。
検索結果を受け取るDeptオブジェクト
public class Dept { private int deptno; private String dname; private String location; public int getDeptno() { return deptno; } public void setDeptno(int deptno) { this.deptno = deptno; } //以下同様なsetter,getter 省略 }
SqlMap
<!-- CSV出力用 --> <select id="csvData" resultClass="examples.dto.Dept"> SELECT DEPTNO, DNAME, LOC as location FROM DEPT ORDER BY DEPTNO desc </select>
SqlMapの記述やBeanの準備は通常の検索と同じです。次にRowHandlerを作成します。
RowHandler
RowHandlerを自作する場合は、RowHandler
インターフェースを実装します。RowHandler
インターフェースはただ1つのhandleRow
メソッドの実装を要求します。
public class CsvRowHandler implements RowHandler { PrintWriter out; /** * 出力ファイルを指定してCSVRowHandlerを生成する * @param outputFile 出力ファイル */ public CsvRowHandler(File outputFile) throws IOException { out = new PrintWriter(new FileWriter(outputFile)); } /** * 1行を処理する */ public void handleRow(Object value) { Dept dept = (Dept)value; out.print(dept.getDeptno()); out.print(","); out.print(dept.getDname()); out.print(","); out.print(dept.getLocation()); out.println(); } /** * ファイルをクローズする。 */ public void close(){ out.close(); } }
コンストラクタでファイル名を指定し、ファイルをオープンします。
handleRow
メソッドは、このRowHandlerが使用される場合に呼び出されます。N件の検索結果を返すSEELCT文では、handleRow
メソッドがN回呼び出されます。引数value
には、SqlMapで定義されたResultClassのオブジェクトが設定されています。つまり今回の例ではDeptオブジェクトが渡されます。
実行プログラム
//CSV出力用RowHandlerを生成 CsvRowHandler rowHandler = new CsvRowHandler(new File("Dept.csv")); //rowHandlerを指定してクエリーを実行 sqlMap.queryWithRowHandler("csvData", rowHandler); //CSVファイルをクローズ rowHandler.close();
queryForList
ではなく、queryWithRowHandler
で実行します。引数で自作したRowHandlerを指定します。
CsvRowHandler
が検索結果の1件1件をファイルに出力します。大量データであっても1件ずつ処理するのでメモリ消費量は取得件数には関係なく、どれだけの大量データを出力しても安定します。
1行ずつ処理したい場合には、RowHandlerを使って任意のコードを記述できます。iBATISのDeveloper Guideでは1件ずつ検索しながらUPDATEを発行する例が紹介されています。