Skip to content
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

[Spring JDBC] 정민주 미션 제출합니다. #396

Merged
merged 11 commits into from
Feb 11, 2025

Conversation

JoungMinJu
Copy link

미션 완성하여 pr 올립니다!
따로 메세지 남길 부분은 없어서 비워두겠습니다.
혹시 궁금하시거나 말씀해주시고 싶으신 부분 있으시면 코멘트 부탁드리겠습니다!

@JoungMinJu JoungMinJu changed the base branch from main to joungminju February 2, 2025 11:28
Copy link

@seokhwan-an seokhwan-an left a comment

Choose a reason for hiding this comment

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

민주님 미션 구현하시느라 고생하셨습니다.
수정했으면 하는 점과 질문 남겼는데 천천히 확인해주시고 답변 달아주세요!

Comment on lines 5 to 6
date VARCHAR(255) NOT NULL,
time VARCHAR(255) NOT NULL,

Choose a reason for hiding this comment

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

현재 미션 진행 설명에서 해당 필드들을 VARCHAR(255)로 해놓았는데
각 필드에 알맞는 타입을 선택하는 것이 좋을 것 같습니다!

URI location = URI.create("/reservations/" + reservation.getId());
return ResponseEntity.created(location).body(reservation);
final Reservation save = reservationRepository.save(reservation);
System.out.println(save);

Choose a reason for hiding this comment

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

해당 출력문을 디버깅 용으로 추가하신 것 같은데 당장 필요는 없어보입니다.

Copy link
Author

Choose a reason for hiding this comment

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

아 맞네요 지우는걸 잊었습니다!! 지워놓겠습니다아

Comment on lines 26 to 38
public Reservation save(Reservation reservation) {
String insertQuery = "INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)";
jdbcTemplate.update(insertQuery, reservation.getName(), reservation.getDate(), reservation.getTime());

String selectSql = "SELECT id, name, date, time FROM reservation WHERE name = ? AND date = ? AND time = ? ORDER BY id DESC LIMIT 1";
return jdbcTemplate.queryForObject(selectSql, (rs, rowNum) ->
new Reservation(
rs.getLong("id"),
rs.getString("name"),
rs.getString("date"),
rs.getString("time")
), reservation.getName(), reservation.getDate(), reservation.getTime());
}

Choose a reason for hiding this comment

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

현재 save 메소드는 reservation을 저장하는 쿼리고 조회하는 쿼리가 발생하고 있습니다. 조회쿼리가 발생하는 이유는 Auto_increment로 생성된 값을 가져오기 위함인 것 같아요. 두번의 db 요청을 보내기 보다는 simpleJdbcInsert를 이용하면 insert 쿼리 만으로도 id 값을 가져올 수 있는데 한번 활용해보는 것도 좋을 것 같습니다!

Copy link

@seokhwan-an seokhwan-an Feb 3, 2025

Choose a reason for hiding this comment

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

추가로 queryForObject는 단일 데이터 조회를 목적으로 만들어진 메소드여서 굳이 ORDER BYLIMIT을 이용할 필요가 없습니다. (2개 이상의 응답 값이 발생하면 예외가 발생하는 것으로 알고 있습니다.)

Copy link
Author

Choose a reason for hiding this comment

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

오 둘 다 모르는 내용이었습니다!! 확인하고 반영하도록 하겠습니다 :)

Copy link
Author

Choose a reason for hiding this comment

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

말씀해주신 simpleJdbcInsert를 활용해 pk를 가져오고
해당 pk를 사용하여 새로운 reservation 객체를 만들 수 있도록 구현하였습니다 ! :)

Comment on lines 14 to 19
public Reservation() {
this.id = null;
this.name = null;
this.date = null;
this.time = null;
}

Choose a reason for hiding this comment

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

현재 해당 생성자는 어떤 상황에서도 이용되지 않아서 지워도 될 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

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

기본생성자가 없음 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of roomescape.entity.Reservation(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator) 에러가 발생하더라구요!

그래서 기본생성자는 일단 살려두고, private으로 선언해두었습니다. 한 번 확인 부탁드리겠습니다!

Copy link

@seokhwan-an seokhwan-an Feb 4, 2025

Choose a reason for hiding this comment

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

확인했습니다!

@@ -23,5 +23,22 @@ public List<Reservation> findAll() {
rs.getString("time")));
}

public Reservation save(Reservation reservation) {
String insertQuery = "INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)";

Choose a reason for hiding this comment

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

JdbcTemplate는 insertQuery와 같이 미리 SQL 형태를 설정하고 ? 에 알맞은 값을 넣어서 처리를 하는데요! 이렇게 SQL의 형태를 미리 설정해두면 어떤 점이 좋은 것일까요?

Copy link
Author

Choose a reason for hiding this comment

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

?에 바인딩되는 형식을 취함으로써
외부에서 입력된 쿼리를 바로 실행하는 것보다 보안적인 부분에서 이득이 있을 것이라 생각합니다!

비슷한 맥락이긴한데, 실제로 PrepareStatement를 사용하면 물음표 안에 들어가는 값에 대한 타입도 제어할 수 있어서 보안상 이점이 있다고 하더라구요 :)

Choose a reason for hiding this comment

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

맞아요 prepareStatement를 활용하면 외부에서 sql injection 공격을 막을 수 있고 민주님 말 대로 타입 제어도 가능해 보안상 장점이 있어요!

Copy link

@seokhwan-an seokhwan-an left a comment

Choose a reason for hiding this comment

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

민주님 답변 남기신 것과 리뷰 반영한 것 확인했습니다.
추가로 수정할 부분이랑 참고사항 남겼는데 확인 부탁드립니다!

Comment on lines 20 to 22
this.simpleJdbcInsert = new SimpleJdbcInsert(source);
this.simpleJdbcInsert.setTableName("reservation");
this.simpleJdbcInsert.usingGeneratedKeyColumns("id");

Choose a reason for hiding this comment

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

이 부분은 참고 사항인데 해당 부분을 이렇게도 표현이 가능하네요

this.simpleJdbcInsert = new SimpleJdbcInsert(source)
            .withTableName("reservation")
            .usingGeneratedKeyColumns("id");

Copy link
Author

Choose a reason for hiding this comment

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

아하 저렇게 하는게 더 가독성이 좋아보이네요 반영해두겠습니다!!

Comment on lines 25 to 32
public List<Reservation> findAll() {
String sql = "SELECT * FROM reservation";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new Reservation(
rs.getString("name"),
rs.getString("date"),
rs.getString("time")));
}

Choose a reason for hiding this comment

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

image

현재 id를 불러오지 않아서 findAll()을 했을 때 예약 번호가 잘 나타나지 않네요 수정 부탁드립니다!

Copy link

@seokhwan-an seokhwan-an left a comment

Choose a reason for hiding this comment

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

민주님 리뷰 모두 반영하신 것 확인했습니다!
현재 데이터를 저장하고 삭제하는 경우에 대해 @transactional 적용하지 않았는데
마지막으로 한 번 이번 api에서는 @transactional 이 필요할지 아닐지를 고민해 보면 좋을 것 같습니다.

@JoungMinJu
Copy link
Author

으악 전혀 생각도 못했는데 Insert나 delete 의 경우엔 @transactional이 필요할 것 같습니다!! 다른 로직에서 에러가 나는 경우 insert 혹은 delete 된 부분을 롤백해야하기 때문입니다 !

Copy link

@seokhwan-an seokhwan-an left a comment

Choose a reason for hiding this comment

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

답변 다신 것 확인했고 마지막으로 간단하게 수정했으면 하는 점 남겼는데 다음 단계에서 진행하면 좋을 것 같습니다!

@@ -1,5 +1,6 @@
package roomescape.controller;

import jakarta.transaction.Transactional;

Choose a reason for hiding this comment

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

트랜잭션 어노테이션은 jakarta에서 제공하는 것이 대신org.springframework.transaction.annotation.Transactional을 이용하는 것이 다양한 속성을 제공하기에 spring 환경에서 유리할 것 입니다.

참고 자료 : https://stackoverflow.com/questions/26387399/javax-transaction-transactional-vs-org-springframework-transaction-annotation-tr

@boorownie boorownie merged commit 2272dd6 into next-step:joungminju Feb 11, 2025
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.

3 participants