작성
·
476
답변 1
3
안녕하세요 한솔님! 질문 남겨주셔서 감사드립니다!! 😊
람다식 부분을 조금 더 알고 싶으셨군요~!! 👍 제가 Step 별로 조금 더 설명드려 보겠습니다.
[1. query 시그니처 살펴보기]
먼저 우리는 우리가 사용하고 싶은 라이브러리의 기능을 확인해보아야 해요!! 즉, JdbcTemplate.query
라는 메소드가 어떻게 생겼는지 알아야~ 해댱 기능을 사용할 수 있죠!
우리가 사용한 JdbcTemplate.query
를 눌러 보면 다음과 같은 메소드 시그니처를 갖고 있습니다. 메소드 시그니처란, 메소드의 이름, 메소드가 받는 매개변수, 반환 결과 등을 의미합니다!!
@Override
public <T> List<T> query(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException {
// 생략
}
보시면 JdbcTemplate
클래스의 query
메소드는 String
타입의 문자열과 RowMapper
타입의 객체, 그리고 Object...
인 가변인자를 받고 있습니다! 여기서 가변인자란, 같은 타입의 값을 여러개 받을 수 있다는 의미입니다.
예를 들어,
public void doSomething(String... strs) {
}
라는 함수가 있으면 우리는 doSomething("A", "B", "C")
와 같이 문자열 여러개를 마음껏 넣을 수 있습니다.
자~ 다음 포인트는 RowMapper
인데요! RowMapper
타입의 객체를 넣어줘야 하죠~ RowMapper
도 어떻게 생겼는지 코드를 눌러 확인해보면, 다음과 같이 생긴걸 알 수 있습니다.
@FunctionalInterface
public interface RowMapper<T> {
@Nullable
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
제네릭과 같이 어려운 부분도 있지만, 가장 직관적으로 알 수 있는 부분은 RowMapper
는 인터페이스이고! mapRow
라는 하나의 메소드를 가지고 있다는 겁니다!! 이제 우리가 사용할 query
가 어떻게 생겼는지 알았으니, 이 기능을 한 번 사용해볼게요!
[2. 가장 원시적인 형태로 query를 호출해보기 작성해보기]
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
jdbcTemplate.query(readSql, [ 여기가 바로 RowMapper가 들어갈 자리 ]], request.getId()).isEmpty();
}
우선 질문주신 RowMapper
부분을 빼놓고 코드를 작성해보았습니다! 여기까지는 이해하시는데 크게 어렵지 않으실거에요~
그럼 이제 RowMapper
를 넣어주어야죠!! 우리가 어떤 타입의 객체를 집어 넣을 때 해당타입의 인스턴스를 집어넣을 수도 있고 그 타입의 하위 클래스의 인스턴스를 집어 넣을 수도 있습니다. 객체의 다형성이죠~ 여기서 RowMapper
는 인터페이스이기 때문에 인터페이스의 인스턴스를 바로 집어 넣을 수 없고, 하위 클래스를 만들어준다음 그 클래스의 인스턴스를 넣어야 합니다.
자 그러면 이렇게 코드를 작성해볼 수 있겠네요
// UserController와는 아예 다른 파일에 위치한 클래스입니다!
// 여기서 <Integer>의 의미는 mapRow의 결과로 Integer를 반환하겠다는 의미입니다.
public class UserFindRowMapper implements RowMapper<Integer> {
@Override
public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
return 0; // readSQL의 결과가 있으면 0으로 바꿔치기한다.
}
}
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
RowMapper<Integer> mapper = new UserFindRowMapper();
jdbcTemplate.query(readSql, mapper], request.getId()).isEmpty();
}
우리는 RowMapper를 넣어주어야 하는데, RowMapper를 바로 넣을 수 없으니 (인터페이스라서요!) RowMapper를 implements 하는 클래스를 만들고 그 클래스의 인스턴스를 넣어주었습니다!
[3. 익명 클래스를 사용해 query 호출해보기]
자 그런데~ 당연히 이런 방법은 번거롭습니다! 새로운 클래스 파일을 만들기 얼마나 귀찮습니까~~ 그래서 바로 "익명 클래스"라는게 등장합니다! 익명 클래스란, 새로운 클래스를 만들지 않고도 어떤 인터페이스를 implements하는 클래스의 인스턴스를 만들어주는 문법입니다. 이걸 적용해보면 코드는 다음과 같이 바뀌게 됩니다.
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
// 여기가 바꼈습니다!!!!!
RowMapper<Integer> mapper = new RowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
return 0;
}
};
jdbcTemplate.query(readSql, mapper, request.getId()).isEmpty();
}
new 인터페이스 이름
으로 익명 클래스를 사용해주었고요~ 아까 새로운 클래스 파일을 하나 만드는 것보다는 훨~~씬 낫습니다!!
[4. 람다식을 사용해 query 호출해보기]
자 하지만 개발자들은 여기서 만족하지 않았습니다. 이 조차도 너무너무 귀찮은거죠! 😅 그래서 어떤 인터페이스의 함수가 하나만 있는 경우는, "람다식"이란걸 쓸 수 있게 합니다.
예를 들어 RowMapper
는 T mapRow(Result rs, int rowNum)
함수를 하나만 가지고 있죠!! 그러면 그냥~ 이렇게 @Override
쓰고~ return 0;
쓰고~ 할 필요 없이
RowMapper<Integer> mapper = new RowMapper<Integer>() {
@Override
public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
return 0;
}
};
이 코드를
RowMapper<Integer> mapper = (rs, rowNum) -> 0;
이렇게!
바꿔버렸습니다. 어차피 함수도 하나니까~ rs만 보더라도 매개변수 ResultSet rs
이란걸 알 수 있고 rowNum
만 보더라도 int rowNum
이란걸 알 수 있죠. 또한 { return 0; }
도 너무 귀찮아서 -> 0
으로 바꿔버렸습니다.
그래서 코드를 다시 한 번 작성해보면,
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
// 여기가 바꼈습니다!!!!!
RowMapper<Integer> mapper = (rs, rowNum) -> 0;
jdbcTemplate.query(readSql, mapper, request.getId()).isEmpty();
}
이렇게 쓸 수 있고요!! 여기서 변수로 굳이 만들지 않고 바로 값을 넣어주면~
@PutMapping("/user")
public void updateUser(@RequestBody UserUpdateRequest request) {
String readSql = "SELECT * FROM user WHERE id = ?";
// 여기가 바꼈습니다!!!!!
jdbcTemplate.query(readSql, (rs, rowNum) -> 0, request.getId()).isEmpty();
}
이렇게 바뀝니다 ㅎㅎㅎ
또 궁금한 점 있으시면 편하게 질문 남겨주세요!! 👍👍👍
감사합니다~!! 🙇🙇
자세히 설명해주셔서 감사합니다~!!