Skip to content

[그리디] 이창희 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

Open
wants to merge 7 commits into
base: chxghee
Choose a base branch
from

Conversation

chxghee
Copy link

@chxghee chxghee commented May 13, 2025

안녕하세요 태연님~~ 😄
리뷰로 뵙는건 처음이네요 잘 부탁드립니다!

이번 미션은 비교적 간단했는데요, 저번 MVC 미션에서 만든 어플리케이션에 DB를 붙이는 미션이었어요
스터디때 페어프로그래밍으로 순수 JDBC만 사용해서 CRUD를 구현해 보고,
이 코드를 Spring JDBC로 고쳐 보았습니다

JDBC를 사용해 보는 것은 처음이라, 제 코드에서 부족한 부분이나 개선할 포인트가 있다면 조언 부탁드립니다!
스프링을 이용하면서 공부해 볼만한 기본 개념같은 것도 소개해 주시면 감사하겠습니다!


구현 내용

  1. H2 데이터 베이스 의존성 추가
  2. spring.sql.init.mode=embedded 옵션으로 어플리케이션 로드 시점에 DDL 실행하여 초기화
  3. Spring JDBC를 이용한 DAO 클래스 구현
    -> DB 접근 책임 위임
  4. 서비스 레이어 DAO 의존 하도록 수정

Copy link

@TaeyeonRoyce TaeyeonRoyce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요, 창희님. 리뷰어로 만나는 건 처음이네요!
Spring에 대해서 충분한 이해도가 있으신 것 같아요.
로직도 명료하고 꼼꼼해서 읽기 좋았습니다!
고생 많으셨어요~~👍👍

몇가지 코멘트 남겨 두었으니 확인해주세요.


추가로, 테스트를 전체적으로 실행 하면 실패합니다.
독립성이 지켜지지 못했어요... 아마 db 초기화와 관련이 있는 문제 같아요.
Screenshot 2025-05-14 at 23 42 41
이 부분도 개선 되면 좋겠네요!
(혹시 제 환경에서만 그런거라면 알려주세요!)


남겨주신 질문

스프링을 이용하면서 공부해 볼만한 기본 개념같은 것도 소개해 주시면 감사하겠습니다!

질문이 너무 방대한 영역을 다루어 답변하기 어렵네요...ㅋㅋㅋ
Spring의 가장 큰 특징인 DIIoC의 개념을 학습하는게 우선인 것 같아요.
내용적으론 별거 없어 보이지만, 이 개념이 프레임워크로서 매우 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() {}

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 범위로 만드신걸로 추측 됩니다...!


근본적인 해결책이 될 수 있을지 궁금해요.
테스트를 위해 직접적으로 쓰이지도 않는 해당 메서드가 존재해서 의도를 파악하기 어려울 것 같아요.
Screenshot 2025-05-14 at 23 39 50

사용 되지 않음이 명확히 보여서... 지우고 싶기도 하고요...!
또, 해당 생성자 때문에 필드들도 불변한 특성이 있음에도 final 키워드를 가져가지 못하게 되는 단점이 있습니다.

어떤 방법으로 해결해 볼 수 있을까요?

@@ -0,0 +1,8 @@
CREATE TABLE reservation
(
id BIGINT NOT NULL AUTO_INCREMENT,

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 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 잘 만드시네요..!👍👍

Comment on lines +45 to +51
(resultSet, rowNum) ->
new Reservation(
resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getDate("date").toLocalDate(),
resultSet.getTime("time").toLocalTime()
)

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)를 추출해서 재사용 할 수 있어요..!

Comment on lines +25 to +27
public Long insert(Reservation reservation) {
final var query = "insert into reservation(name, date, time) values(?, ?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();

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 {

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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional로 반환하는 이유가 있을까요?

Comment on lines +41 to +45
assertSoftly(soft -> {
soft.assertThat(findReservations).hasSize(2);
soft.assertThat(findReservations.get(0).getName()).isEqualTo("이창희");
soft.assertThat(findReservations.get(1).getName()).isEqualTo("전서희");
});

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

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) 환경에서만 실행을 보장 할 수 있게 되었어요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants