스프링이 제공하는 JDBC 코드용 기본 템플릿은 JdbcTemplate 이다.
private JdbcTemplate = new JdbcTemplate(dataSource);
PreparedStatementCreator 인터페이스의 createPreparedStatement() 콜백 메서드를 지원한다.
템플릿으로부터 Connection을 제공받아 PreparedStatement를 만들ㄹ어 돌려준다.
PreparedStatementCreator 타입의 콜백을 받아서 사용하는 JdbcTemplate 템플릿 메소드는 update()다.
기존 add , deleteAll -> update()
add() {
jdbcTemplate.update("insert into users(id,name,password) values (?,?,>?)", user.getId(),user.getName(),user.getPassword());
}
deleteAll(){
jdbcTemplate.update("delete from users");
}
ResultSet 을 결과로 받는 작업 흐름을 가진 코드에서 사용할 수 있는 템플릿은 PreparedStatementCreator 콜백과 ResultSetExtractor 콜백을 파라미터로 받는 query() 메서드다
ResultSetExtractor 는 PreparedStatement 의 쿼리를 실행해서 얻은 ResultSet을 전달 받는 콜백이다. ResultSet을 이용해 원하는 값을 추출해서 템플릿에 전달하면, 템플릿은 나머지 작업을 수행 후 그 값을 query의 메서드의 리턴값으로 돌려준다.
public int getCount() throws SQLException {
return jdbcTemplate.query(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
return connection.prepareStatement("select count(*) from users");
}
}, new ResultSetExtractor<Integer>(){
@Override
public Integer extractData(ResultSet resultSet) throws SQLException, DataAccessException {
resultSet.next();
return resultSet.getInt(1);
}
});
}
위처럼 사용하면 되고 위의 기능을 가진 콜백을 내장하고 있는 queryForInt()라는 메소드를 사용할 수도 있다.
public int getCount() throws SQLException {
return jdbcTemplate.queryForInt("select count (*) from users");
get() ->
SQL은 바인딩이 필요한 치환자를 갖고 있고,
ResultSet의 결과를 User 오브젝트를 만들어 프로퍼티에 넣어줘야함
이를 위해 ResultSetExtractor 콜백 대신 RowMapper 콜백을 사용한다.
둘 다 템플렛으로부터 ResultSet을 전달받고 필요한 정보를 추출해서 리턴하는 방식인데, 전자는 한 번 전달받아 알아서 추출 작업이 모두 진행되 최종 결과만 리턴해주면 되는데, 후자는 ResultSet의 로우 하나를 매핑하기에위해 사용되기 때문에 여러번 호출 될 수 있더.
return jdbcTemplate.queryForObject("select * from users where id=?",
new Object[]{id}, // SQL에 바잉딩할 파라미터 값, 가변인자 대신 배열을 사용한다.
new RowMapper<User>() {
@Override
public User mapRow(ResultSet resultSet, int rowNum) throws SQLException {
User user = new User();
user.setId(resultSet.getString("id"));
user.setName(resultSet.getString("name"));
user.setPassword(resultSet.getString("password"));
return user;
}
});
바인딩할 값 (id) 에 배열을 보낸 이유는 바인딩 할 값이 마지막 파라티터가 아니기 때문에 가변인자로 정의 할 수 없기 때문이다.
queryForObject() 는 SQL을 실행시키면 한개의 로우만 얻을 것이라고 기대한다. 그리고 ResultSet의 next()를 실행한후 RowMapper 콜백을 호출한다.
queryForObject() 를 사용했을때 예외처리 방법 : jdbc가 알아서 해준다.
기능 정의와 테스트 작성
queryForObject() 는 쿼리의 결과가 로우 하나일 때 사용하고 query()는 여러개의 로우가 결과로 나오는 일반적인 경우에 사용한다.
모든 로우를 열람하면서 로우마다 RowMapper() 콜백을 후출한다.