JdbcTemplateを使用して、データベースをストリーミング(カーソル)で読み取る

JdbcTemplateのストリーミング(カーソル)fetchは、fetchSizeプロパティを設定することで実現できます。fetchSizeプロパティは、データベースから一度に取得するレコード数を指定するために使用します。以下にサンプルコードを示します。

public class JdbcTemplateExample {
private JdbcTemplate jdbcTemplate;
public JdbcTemplateExample(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public List<User> getUsers() {
String sql = "SELECT * FROM users";
List<User> userList = jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
return user;
}
});
return userList;
}
public Stream<User> getUsersAsStream() {
String sql = "SELECT * FROM users";
jdbcTemplate.setFetchSize(1000);
jdbcTemplate.query(sql, new ResultSetExtractor<Stream<User>>() {
@Override
public Stream<User> extractData(ResultSet rs) throws SQLException, DataAccessException {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(new ResultSetIterator(rs), Spliterator.ORDERED),
false);
}
});
}
}
class ResultSetIterator implements Iterator<User> {
private ResultSet rs;
public ResultSetIterator(ResultSet rs) {
this.rs = rs;
}
@Override
public boolean hasNext() {
try {
return rs.next();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public User next() {
try {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
return user;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}

上のコードでは、getUsersメソッドは普通のJdbcTemplateクエリメソッドを使用してクエリ結果をListオブジェクトに変換して返しています。それに対して、getUsersAsStreamメソッドはResultSetExtractorを使用してクエリ結果をStreamオブジェクトに変換して返しています。ResultSetExtractorでは、ResultSetIteratorをspliteratorUnknownSizeにパラメータとして渡すことで、ResultSetをStreamに変換しています。ResultSetIteratorはIteratorインタフェースを実装しており、Streamで使用することができます。

ストリームでDBを参照する際には、fetchSizeを適切に設定し、一度に取得するレコードの数を制御することが重要です。小さいfetchSizeはメモリの消費を抑えますが、クエリの実行回数を増やします。対して、大きなfetchSizeはクエリの実行回数を減らしますが、メモリの消費を増やします。用途に応じて適切なfetchSizeをご選択ください。

bannerAds