- 履歴一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 障害メモ/PreparedStatementがOutOfMemoryErrorを起こす へ行く。
- 1 (2015-08-11 (火) 07:34:50)
キーワード†
- MySQL
- PreparedStatement
- ResultSet
- OutOfMemoryError
現象†
一行ずつResultSetからデータ取得しているはずなのにOutOfMemoryErrorになる。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.mysql.jdbc.MysqlIO.nextRowFast(MysqlIO.java:1649) at com.mysql.jdbc.MysqlIO.nextRow(MysqlIO.java:1426) at com.mysql.jdbc.MysqlIO.readSingleRowSet(MysqlIO.java:2924) at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:477) at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:2619) at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1788) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2209) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2281)
原因†
すべての行をfetchしてResultSetを生成しようとするようです。なので、取得対象が膨大になるとすぐにOutOfMemoryErrorを起こします。
一行ずつ取得するようにした実装が泣くね。
対策†
一定行ずつfetchするようにMySQLを設定します。
接続プロパティで指定する方法†
次のクエリストリングを接続プロパティに加えます。
useCursorFetch=true&defaultFetchSize=100
100は一度にfetchする行数のよう。
コードで指定する方法†
stmt = conn.createStatement( java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY ); stmt.setFetchSize(Integer.MIN_VALUE);