Template Callback 적용
jdbcContext로 전략패턴을 주입하는 부분도 반복됩니다. 이 부분도 메소드로 분리하여 반복을 줄일 수 있습니다.
public void executeSql(String sql) {
this.workWithStatementStrategy(new StatementStrategy() {
@Override
public PreparedStatement makePreparedStatement(Connection connection) throws SQLException {
PreparedStatement stmt = connection.prepareStatement(sql);
return stmt;
}
});
}
public void deleteAll() thorws SQLException {
this.executeSql("delte from users");
}
Java
복사
•
다음과 같이 sql 쿼리만 넘겨주도록 설계할 수 있습니다.
하지만 executeSql은 UserDao에 두기에는 아깝습니다. HospitalDao와 같은 다른 Dao도 사용할 수 있도록 공유 템플릿 클래스에 옮기면 필요할 때마다 가져와서 사용할 수 있습니다.
UserDao.java
public void deleteAll() thorws SQLException {
this.jdbcContext.executeSql("delte from users");
}
Java
복사
JdbcContext.java
public void executeSql(String sql) {
this.workWithStatementStrategy(new StatementStrategy() {
@Override
public PreparedStatement makePreparedStatement(Connection connection) throws SQLException {
return connection.prepareStatement(sql);
}
});
}
Java
복사
•
결국 그림과 같이 UserDao가 JdbcContext를 의존하면서 template과 client, callback을 사용하는 구조가 되었습니다. 이 방식으로 add()에도 적용할 수 있습니다.
JdbcTemplate 적용
private final JdbcTemplate jdbcTemplate;
public UserDao(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
Java
복사
deleteAll 수정
이전에 사용한 콜백( StatementStrategy 인터페이스의 makePreparedStatement() 메서드 )은 Template 콜백( PreparedStatementCreator 인터페이스의 createPreparedStatement() 메서드 )과 같음
익명 클래스를 통해 PreparedStatementCreator 인터페이스를 구현 / 커넥션을 인자로 하는 createPreparedStatement 메서드를 오버라이딩하여 sql 구문을 실행하는 과정
// 내장 콜백 함수를 사용
public void deleteAll() {
jdbcTemplate.update("delete from users");
}
Java
복사
add() 수정
update()에서 sql구문과 바인딩할 파라미터를 순서에 유의하여 추가만 해주면 된다.
public void add(final User user) {
jdbcTemplate.update("insert into users(id,name,password) values (?,?,?)", user.getId(),user.getName(),user.getPassword());
}
Java
복사
getCount() 수정
public int getCount() throws SQLException {
return jdbcTemplate.queryForObject("select count(*) from users",Integer.class);
}
Java
복사
파라미터( select count(*) from users ) : PreparedStatment를 만들기 위한 SQL
파라미터 : Integer.class를 넘겨줌으로써 int형의 데이터를 받아옴
SelectById() 수정
public User selectById(String id) {
String sql = "select * from users where id = ?";
return jdbcTemplate.queryForObject(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
return user;
}
}, id);
}
Java
복사
파라미터( “select * from users where id = ? ) : PreparedStatment를 만들기 위한 SQL
파라미터 ( RowMapper 콜백) : 현재 ResultSet이 가르키고 있는 로우의 내용을 User에 담아서 리턴
파라미터( new Object[] {id} ) : 바인딩할 값들 ( 여러 개 일 경우 배열 사용 )
getAll() 추가
public List<User> getAll() {
String sql = "select * from users order by id";
return this.jdbcTemplate.query(sql, new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
return user;
}
});
}
Java
복사
파라미터( “select * from users order by id) : PreparedStatment를 만들기 위한 SQL
파라미터 : 바인딩할 값들 ( 없다면 생략 가능 )
파라미터 ( RowMapper 콜백 ) : 현재 ResultSet이 가르키고 있는 로우의 내용을 User에 담아서 리턴
최종적으로 RowMapper는 로우의 개수만큼 호출되며 가져온 모든 User를 List에 담아서 리턴 해줍니다.
재사용 가능한 콜백의 분리
중복 제거
// selectById() 와 getAll() 함수 중 RowMapper 중복 존재하므로 분리
RowMapper<User> rowMapper = new RowMapper<User>() {
@Override
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User(rs.getString("id"), rs.getString("name"), rs.getString("password"));
return user;
}
};
public User selectById(String id) {
String sql = "select * from users where id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}
public List<User> getAll() {
String sql = "select * from users order by id";
return this.jdbcTemplate.query(sql, rowMapper);
}
Java
복사
RowMapper
행 단위로 ResultSet의 행을 매핑하기 위해 JdbcTemplate에서 사용하는 인터페이스