DBFlute -- 「大量データをCSV出力」の実装検討(自問自答)


10万件のレコードを一気にCSVファイルへ出力するような場合の話。

別にDBFluteの提供するHelperを使う必要は無いですが、
もし使うとすればどうなるかなとちょっとお試し実装。
(CursorHandlerとFileTokenの連携)

しかし、もうちょい工夫できそうな...

HeaderInfoで列定義の順序を決めているので、値の設定も名前解決できるか!?
HashMapのキー値に列名を指定するような感じ。(どうだろう...大して変わらないか)

あと、もうCSV出力専用SQLであることが多いと思うので、列定義順序はSQLのSelect句
通りであることを考慮すると、せっかくSql2EntityでSelect句ハンドリングできるのだから
XxxCursorHandler()の中にこのへんの支援を入れてもいいかも。
但し、文字列とか数値はいいが、日付だけはそれぞれのフォーマットがあると
思うので、Superクラスで一律toString()で作成ってわけにはいかないかな。

FileTokenのmake()は、OutputStreamを引数にしたオーバーロードがいます。
WEBでCSVをダウンロードなんてやつときはそちらを使います。
(実案件で使ってリリースして今も動いています)

【BehaviorのGapクラスでの実装】
※でわさんのアドバイスをもらって、はてなJava記述を使ってみました。

final String filename = "/tmp/xxx.csv";// 本当はちゃんとしたところから取得
final List<String> valueList new ArrayList<String>();
final XxxCursorHandler handler = new XxxCursorHandler() {
    public Object fetchCursor(final XxxCursor cursor) throws SQLException {
        final FileToken fileToken = new FileTokenImpl();// 本当はDIコンポーネントでもOK
        final FileMakingCallback callback = new FileMakingCallback() {
            public FileMakingRowResource getRowResource() {
                if (!cursor.next()) {
                    return null;
                }
                final List<String> valueList new ArrayList<String>();
                valueList.add(cursor.getBookId().toString());
                valueList.add(cursor.getBookName();
                valueList.add(cursor.getGenreCode());
                valueList.add(cursor.getUTimestamp().toString());// 本当はFormatとかする!?
                ...
                final FileMakingRowResource resource = new FileMakingRowResource();
                resource.setValueList(valueList);
                return resource;
            }
        }
        final FileMakingOption option = new FileMakingOption();
        final FileMakingHeaderInfo headerInfo = new FileMakingHeaderInfo();
        final List<String> columnNameList = new ArrayList<String>();
        columnNameList.add(XxxCursor.DB_NAME_BOOK_ID);
        columnNameList.add(XxxCursor.DB_NAME_BOOK_NAME);
        columnNameList.add(XxxCursor.DB_NAME_GENRE_CODE);
        columnNameList.add(XxxCursor.DB_NAME_U_TIMESTAMP);
        ...
        final FileMakingHeaderInfo headerInfo = new FileMakingHeaderInfo();
        headerInfo.setColumnNameList(columnNameList);
        option.setFileMakingHeaderInfo(headerInfo);
        option.delimitateByComma().encodeAsUTF8().separateLf();// カンマ区切りでUTF8で改行はLF
        fileToken.make(filename, callback, option);
    }
}
getMyDao().selectListXxx(pmb, handler);// これはアプリ独自のメソッド