*설정은 순수 Jdbc와 동일하게 환경설정을 하면 된다.
스프링 JdbcTemplate은 MyBatis와 비슷한 라이브러리인데,
JDBC API에서의 반복적인 코드를 제거해준다.
(sql은 직접 작성해주긴 해야 한다.)
우선 repository에 JdbcTemplateMemberRepository 클래스를 생성한다.
MemberRepository를 implements 해준 후,
option + enter 로 implements method를 해주었다.
그리고 JdbcTemplate를 정의해준 후,
Constructor를 생성해주었다.
@Autowired
public JdbcTemplateMemberRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
이렇게 datasource를 injection 해주고,
jdbcTemplate에 dataSource를 넣어주었다.
*참고) 생성자가 딱 하나만 있으면, @Autowired 생략이 가능하다.
조회하는 query를 먼저 해보면,
@Overridepublic Optional<Member> findById(Long id) {
return jdbcTemplate.query("select + from member where id = ?", );
}
를 작성하고,
결과가 나오는 것을 rowMapper로 mapping을 해주어야 하는데,
그것을 제일 하단에 작성하였다.
private RowMapper<Member> memberRowMapper(){
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
코드는 이러하다.
위 코드는
private RowMapper<Member> memberRowMapper(){
return new RowMapper<Member>() {
@Override
public Member mapRow(ResultSet rs, int rowNum) throws SQLException { Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
}
}
를 option + enter로 람다함수로 바꿔준 코드이다.
그리고 다시 findById로 돌아가서,
코드를 마무리한다.
@Overridepublic
Optional<Member> findById(Long id) {
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper());
return result.stream().findAny();
}
이 과정들은
이전에 순수 jdbc 코드로 작성하였던 것보다 훨씬 간단하다.
jdbcTemplate 라이브러리로 이렇게 간단하게 줄일 수 있는 것이다.
이제 save를 작성해보겠다.
@Overridepublic
Member save(Member member) {
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
Map<String, Object> parameters = new HashMap<>();
parameters.put("name", member.getName());
Number key = jdbcInsert.executeAndReturnKey(new
MapSqlParameterSource(parameters));
member.setId(key.longValue());
return member;
}
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
여기서 SimpleJdbcInsert라는 기능이 있는데,
jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
로 넣으면,
query를 짤 필요가 없게 된다.
→ Document를 보면 친절하게 다 나와있으니 보고 하면 된다.
*이렇게 하는구나 정도만 알면 됨.
findByName과 findAll도
findById와 비슷하게 각각
@Overridepublic
Optional<Member> findByName(String name) {
List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper());
return result.stream().findAny();
}
@Overridepublic
List<Member> findAll() {
return jdbcTemplate.query("select * from member", memberRowMapper());
}
이렇게 코드를 작성해 주었다.
*사용법은 jdbcTemplate menual 검색하면 많이 나오니까 참고 (김영한씨도 data 접근 기술 강의할 때 깊이있게 설명해줄 예정)
정리하자면,
findById는 jdbcTemplate에서 query를 날리고,
그 결과를 memberRowMapper를 통해서 mappingg하고,
List로 받아서 optional로 바꿔서 반환해준다.
findByName도 똑같은 과정을 거치고
findAll은 어차피 select * from member를 list로 반환해주기 때문에 간단하다.
그 결과를
RowMapper에서 Member 객체로 mapping을 한 후에 돌려주면 된다.
이렇게 JdbcTemplateMemberRepository를 모두 작성하였고,
SpringConfig에서 조립해준다.
@Beanpublic
MemberRepository memberRepository() {
//return new MemoryMemberRepository();
//return new JdbcMemberRepository(dataSource);
return new JdbcTemplateMemberRepository(dataSource);
}
이렇게 새로운 JdbcTemplateMemberRepository를 추가해주었고,
이제 실행을 해 볼 차례이다.
우리는 spring 통합 test를 만들어 놓았기 때문에,
웹 어플리케이션을 띄워서 검증해 볼 필요가 없이
MemberServiceIntegrationTest를 돌려보면 된다.
오류가 떴다.
살펴보니 parameter가 제대로 setting되지 않았다는 오류이다.
@Overridepublic Optional<Member> findById(Long id) {
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
return result.stream().findAny();
}
@Overridepublic
Optional<Member> findByName(String name) {
List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
return result.stream().findAny();
}
findById와 findByName에 parameter id, name을 추가해주지 않아서 뜬 오류이므로 수정해주고,
다시 실행해보았더니 제대로 실행된 모습을 볼 수 있었다.
(*단축키: control + r → 마지막에 실행한 것을 재실행)
====⇒ JdbcTemplate 버전의 db까지 연동한 test가 실제로 성공한 것