-
Notifications
You must be signed in to change notification settings - Fork 147
[그리디] 이창희 JDBC 미션 5,6 단계 제출합니다 #444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: chxghee
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요, 창희님. 리뷰어로 만나는 건 처음이네요!
Spring에 대해서 충분한 이해도가 있으신 것 같아요.
로직도 명료하고 꼼꼼해서 읽기 좋았습니다!
고생 많으셨어요~~👍👍
몇가지 코멘트 남겨 두었으니 확인해주세요.
추가로, 테스트를 전체적으로 실행 하면 실패합니다.
독립성이 지켜지지 못했어요... 아마 db 초기화와 관련이 있는 문제 같아요.
이 부분도 개선 되면 좋겠네요!
(혹시 제 환경에서만 그런거라면 알려주세요!)
남겨주신 질문
스프링을 이용하면서 공부해 볼만한 기본 개념같은 것도 소개해 주시면 감사하겠습니다!
질문이 너무 방대한 영역을 다루어 답변하기 어렵네요...ㅋㅋㅋ
Spring의 가장 큰 특징인 DI
와 IoC
의 개념을 학습하는게 우선인 것 같아요.
내용적으론 별거 없어 보이지만, 이 개념이 프레임워크로서 매우 powerful 한 특성인 것 같아요.
그리고 이를 잘 활용하기 위한 근간 개념이기도 하고요.
Jdbc 미션을 하면서 jdbcTemplate
을 사용 했었죠. 창희님은 정의한 적도 없는 해당 객체를 주입 받았고, 창희님이 제작중인 애플리케이션에 맞게 Reservation
스키마에 맞는 profile을 정의 하고나니 너무나도 쉽게 DB에 접근을 할 수 있게 되었죠.
뿐만 아니라 Controller에선 dto만 정의해도 json 데이터가 객체로 변환 되고, new
라는 키워드 없이, 구체 클래스를 지정한 적도 없이, 정의한 객체(빈)이 각각의 의존성을 지키며 로드 되었어요.
이러한 구조, 방식이 어떤 이점이 있을 지 고민해보면 좋아요.
Spring core에서 갖고 있는 철학에 대해 학습 하셔도 좋을 것 같네요.
major 기술의 장점 중의 하나가 자료가 많은거잖아요..?!
다양한 spring 면접 질문들, 기업의 용례들을 살펴보면 좋습니다!
@@ -11,13 +11,21 @@ public class Reservation { | |||
private LocalDate date; | |||
private LocalTime time; | |||
|
|||
protected Reservation() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
의문이 드는 생성자네요..!
파악해보니 아래 테스트를 위해 존재하는 것 같군요.
MissionStepTest.class
@Test
void 육단계() {
jdbcTemplate.update("INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)", "브라운", LocalDate.parse("2023-08-05"), LocalTime.parse("15:40"));
List<Reservation> reservations = RestAssured.given().log().all()
.when().get("/reservations")
.then().log().all()
.statusCode(200).extract()
.jsonPath().getList(".", Reservation.class);
Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(reservations.size()).isEqualTo(count);
}
아마 생성자가 한개보다 많이 존재 하여 jackson이 어떤 생성자를 참고하여 만들지 결정 되지 않는 오류를 접하신 것 같아요.
그래서 인자가 없는 생성자를 proctected
범위로 만드신걸로 추측 됩니다...!
근본적인 해결책이 될 수 있을지 궁금해요.
테스트를 위해 직접적으로 쓰이지도 않는 해당 메서드가 존재해서 의도를 파악하기 어려울 것 같아요.
사용 되지 않음이 명확히 보여서... 지우고 싶기도 하고요...!
또, 해당 생성자 때문에 필드들도 불변한 특성이 있음에도 final 키워드를 가져가지 못하게 되는 단점이 있습니다.
어떤 방법으로 해결해 볼 수 있을까요?
@@ -0,0 +1,8 @@ | |||
CREATE TABLE reservation | |||
( | |||
id BIGINT NOT NULL AUTO_INCREMENT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
id의 경우 관성적으로 Bigint를 사용하는데, int로 지정 하면 문제가 있을까요?
또, id 생성 전략은AUTO_INCREMENT
말고 어떤 것들이 있을까요? 해당 전략은 분산 환경에서 문제가 발생 할 수도 있어요. (현재는 아무 문제 없음)
id의 경우 당연하게, 자연스럽게 정의 하게 되는데 한번씩 의심의 눈초리로 보면 재밌답니다...!
한 번 찾아보시면서 학습해보면 좋을 것 같아요!
|
||
@SpringBootTest | ||
@Transactional | ||
class ReservationDAOTest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트 잘 만드시네요..!👍👍
(resultSet, rowNum) -> | ||
new Reservation( | ||
resultSet.getLong("id"), | ||
resultSet.getString("name"), | ||
resultSet.getDate("date").toLocalDate(), | ||
resultSet.getTime("time").toLocalTime() | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jdbcTemplate
을 통해 조회한 데이터를 entity로 변환 하는 작업은 자주 활용 되어요!
findAll(), findByXXX()... 등 모든 곳..
객체로 변환하는 RowMapper
를 항상 파라미터로 받는데, 해당 인터페이스(RowMapper)를 추출해서 재사용 할 수 있어요..!
public Long insert(Reservation reservation) { | ||
final var query = "insert into reservation(name, date, time) values(?, ?, ?)"; | ||
KeyHolder keyHolder = new GeneratedKeyHolder(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
키홀더를 통해 DB에서 생성된 id 값도 가져오셨군요. 좋은 방법입니다!
하지만, spring에서 더 간략한 방식을 제공하는 것을 알고 계셨나요?
simplejdbcinsert
에 대해서도 한번 훑어보세요!
참고 하실 수 있는 자료 남겨 두겠습니다.
import java.util.Optional; | ||
|
||
@Component | ||
public class ReservationDAO { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
추후 spring으로 프로젝트를 구성하면 필연적으로 지금처럼 DB와의 상호작용이 필요하게 됩니다.
그땐 아마도, DAO라는 네이밍의 객체보단 Repository라는 네이밍도 접하게 될 거에요.
둘의 차이에 대해서 살펴보시면 좋을 듯 합니다. 어떻게 다를까요?
); | ||
} | ||
|
||
public Optional<Reservation> findById(Long id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional로 반환하는 이유가 있을까요?
assertSoftly(soft -> { | ||
soft.assertThat(findReservations).hasSize(2); | ||
soft.assertThat(findReservations.get(0).getName()).isEqualTo("이창희"); | ||
soft.assertThat(findReservations.get(1).getName()).isEqualTo("전서희"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SoftAssertion 👍👍
일반적인 assertion을 열거하는 것과 어떤 차이가 있는지도 학습하시면 좋을 것 같아요!
spring.datasource.username=sa | ||
spring.datasource.password= | ||
|
||
spring.sql.init.mode=embedded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트 환경에 적합한 좋은 방식이네요! 👍
정의한 schema.sql
혹은 data.sql
은 embedded-db(h2) 환경에서만 실행을 보장 할 수 있게 되었어요.
안녕하세요 태연님~~ 😄
리뷰로 뵙는건 처음이네요 잘 부탁드립니다!
이번 미션은 비교적 간단했는데요, 저번 MVC 미션에서 만든 어플리케이션에 DB를 붙이는 미션이었어요
스터디때 페어프로그래밍으로 순수 JDBC만 사용해서 CRUD를 구현해 보고,
이 코드를 Spring JDBC로 고쳐 보았습니다
JDBC를 사용해 보는 것은 처음이라, 제 코드에서 부족한 부분이나 개선할 포인트가 있다면 조언 부탁드립니다!
스프링을 이용하면서 공부해 볼만한 기본 개념같은 것도 소개해 주시면 감사하겠습니다!
구현 내용
spring.sql.init.mode=embedded
옵션으로 어플리케이션 로드 시점에 DDL 실행하여 초기화-> DB 접근 책임 위임