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

[JDBC 라이브러리 구현] 리오(오영택) 1단계 미션 제출합니다. #307

Merged
merged 7 commits into from
Sep 29, 2023

Conversation

Jaeyoung22
Copy link

안녕하세요 바론! 연휴 잘 보내고 계신가요?!
JDBC 라이브러리 구현해서 보냅니다!
리뷰 잘 부탁드려요~!

Copy link

@somsom13 somsom13 left a comment

Choose a reason for hiding this comment

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

안녕하세요 리오~!~!!! 바론입니다 🙇‍♀️

구현을 엄청나게 잘 하셔서 어쩌다보니 엄지척 남긴 코멘트가 전체 코멘트의 절반이 된 것 같네요... 머쓱 👍 👍 👍

리오가 확인해주셨으면 하는 코멘트가 조금 있어서 Request Change로 남겨둡니다..!! 편하게 확인하시구 다시 리뷰 요청 주시면 감사하겠습니다 ㅎㅎ

1단계 고생하셨어요~!!!!! 👍

.isThrownBy(() -> this.template.update(sql))
.withCause(sqlException);
verify(this.preparedStatement).close();
verify(this.connection, atLeastOnce()).close();

Choose a reason for hiding this comment

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

다른 테스트에서는 connection을 verify(this.connection).close() 로 검증하셨는데, 예외 테스트들에서는 atLeastOnce 라는 조건을 추가하셨군요!!

예외 테스트에는 한 번 이상 호출 이라는 조건을 추가하신 이유가 궁금해요~!~! 😄

Copy link
Author

Choose a reason for hiding this comment

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

좋은 질문이네요!!

정상적인 상황에서는 명시적으로 한 번만 호출되었음을 가정하기 때문에 atLeastOnce()를 붙이지 않았어요.

그러나 예외의 상황에서는 SQLException이 몇 번 발생됐는지를 확인할 수도 없고 확인할 필요도 없을 것 같아요!
그래서 어쨌든 무조건 커넥션을 닫는다는 뜻을 추가하기 위해서 추가했어요!

혹시 설명이 부족해서 이해가 안되시면 DM으로 언제든지 질문해주세요!

Choose a reason for hiding this comment

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

오호 이해 너무 잘 됐습니다
감사합니다 ㅎㅎ 테스트 장인이시네요...

Comment on lines +71 to +74
@FunctionalInterface
public interface RowMapper<T> {
T run(ResultSet resultSet) throws SQLException;
}
Copy link

@somsom13 somsom13 Sep 29, 2023

Choose a reason for hiding this comment

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

RowMapper 인터페이스를 jdbcTemplate 내부에 두셨군요!!
확실히 JdbcTemplate을 통해서 쿼리 작업을 수행하도록 하는 지금 미션에서는 RowMapper가 JdbcTemplate 내에 있어도 좋을 것 같아요 👍 👍

그런데 만약 ADao에서는 JdbcTemplate을 사용하고 BDao에서는 NamedParameterJdbcTemplate를 사용하는 것 처럼 여러 템플릿을 함께 사용하게 된다면, BDao에서는 JdbcTemplate이 필요하지 않음에도 JdbcTemplate.RowMapper를 사용해야 할 것 같아요.

이런 상황에 대해서 리오는 어떻게 생각하시는지 궁금해요!!

지금 미션에서는 생기지 않을 상황이라 괜한 고민인가..? 싶지만 리오의 의견이 궁금해서 코멘트 남깁니다!!

Copy link
Author

Choose a reason for hiding this comment

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

넵ㅎㅎ 저도 고민을 많이 했고 리뷰를 주실 것 같았는데 역시나 주셨군요 ㅎㅎ...
저도 외부로 분리할까 많이 고민을 했는데요, 저희가 NamedParameterJdbcTemplate을 구현해야하는 상황 처럼
확장성을 고려해야할 때 분리를 하는 것이 맞지 않는가... 싶어서 우선은 내부에 두었습니다!
그런데 계속 찜찜해서 2단계 때 분리하려구요...ㅎㅎ 커멘트 감사합니다!

Copy link

@somsom13 somsom13 Sep 29, 2023

Choose a reason for hiding this comment

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

저희가 NamedParameterJdbcTemplate을 구현해야하는 상황 처럼 확장성을 고려해야할 때 분리를 하는 것이 맞지 않는가...

저는 이것도 너무 좋은 생각이라고 생각합니다 ㅎㅎ 리오의 결정에 따라 분리하시면 좋을 것 같아요!! 😄

public UserDao(final DataSource dataSource) {
this.dataSource = dataSource;
private final JdbcTemplate jdbcTemplate;
private final JdbcTemplate.RowMapper<User> rowMapper = resultSet -> {

Choose a reason for hiding this comment

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

RowMapperstatic으로 선언하지 않은 이유가 궁금해요~!

Copy link
Author

Choose a reason for hiding this comment

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

UserDao에서만 쓰이도록 타입까지 명시를 해놔서요, UserDao가 생성될 때 한번만 호출되면 되지 않나 생각을 했는데 생각을 해보니 현재 Bean으로 등록이 되지 않은 클래스였네요...
static을 붙이지 않아서 UserDao가 생길 때마다 계속 생성되야하니까 메모리 누수가 있겠네요ㅠㅠㅠㅠ
커멘트 감사합니다!

}
} catch (SQLException ignored) {}
public void insert(User user) {
String sql = "insert into users (account, password, email) values (?, ?, ?)";

Choose a reason for hiding this comment

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

사소한 내용이지만 일부 메서드는 파라미터나 지역 변수에 final 키워드가 붙어있고, 그렇지 않은 메서드들도 있는 것 같아요!

혹시 final 키워드를 붙이는 리오만의 기준이 있으신가요?.?

Copy link
Author

Choose a reason for hiding this comment

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

앗 저는 final을 붙이지 않는 것을 선호합니다..! 있다가 없다가 하면 좀 헷갈리더라구요.. ㅎㅎ..
보이는 final들을 다 지운다고 지워봤는데 남아있는 것이 있었군요..! 싹 다 지우겠습니다!

Comment on lines 67 to 69
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... values) {
return query(sql, rowMapper, values).get(0);
}
Copy link

@somsom13 somsom13 Sep 29, 2023

Choose a reason for hiding this comment

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

query의 결과가 비어있는 리스트라면 get(0) 을 했을 때 어떤 결과가 나오나요?.?

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

@somsom13 somsom13 left a comment

Choose a reason for hiding this comment

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

안녕하세요 리오~~~

리뷰 반영 엄청 빠르게 해주셨네요 👍 👍 (하지만 저의 리뷰는 그렇게 빠르지 못했죠 죄송합니다..)
리뷰 반영도 완벽하게 해주셨고 1단계 요구사항도 아주 깔끔하게 만족해주신 것 같아서 approve 하겠습니다

고생 많으셨습니다!!!!! 즐거운 추석 연휴 보내시고 2단계에서 뵐게요~!~!!

.isThrownBy(() -> this.template.update(sql))
.withCause(sqlException);
verify(this.preparedStatement).close();
verify(this.connection, atLeastOnce()).close();

Choose a reason for hiding this comment

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

오호 이해 너무 잘 됐습니다
감사합니다 ㅎㅎ 테스트 장인이시네요...

Comment on lines +71 to +74
@FunctionalInterface
public interface RowMapper<T> {
T run(ResultSet resultSet) throws SQLException;
}
Copy link

@somsom13 somsom13 Sep 29, 2023

Choose a reason for hiding this comment

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

저희가 NamedParameterJdbcTemplate을 구현해야하는 상황 처럼 확장성을 고려해야할 때 분리를 하는 것이 맞지 않는가...

저는 이것도 너무 좋은 생각이라고 생각합니다 ㅎㅎ 리오의 결정에 따라 분리하시면 좋을 것 같아요!! 😄

Comment on lines +72 to +76
List<T> result = query(sql, rowMapper, values);
if (result.isEmpty()) {
return null;
}
return result.get(0);

Choose a reason for hiding this comment

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

👍 👍

@@ -57,15 +58,22 @@ public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... values) {
result.add(rowMapper.run(resultSet));
}

resultSet.close();
Copy link

@somsom13 somsom13 Sep 29, 2023

Choose a reason for hiding this comment

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

resultSet.close()를 추가해주셨네용! 저도 이 부분에 대해서 고민을 많이 했었는데, ResultSet의 close메서드를 보니

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results.

라고 적혀있더라구요!

Statement의 close 메서드에도 다음과 같이 적혀있었어요.

Note:When a Statement object is closed, its current ResultSet object, if one exists, is also closed.

혹시 몰라 UserDaoTest를 통해 디버깅도 한 번 해봤는데, JdbcResultSet에서 closeInternal이 호출되는 걸 확인할 수 있었어요.

그래서 저는 resultSet.close를 별도로 호출하지 않기로 결정했는데, 리오의 의견도 나중에 알려주시면 좋을 것 같아요 ㅎㅎ

혹시 제가 잘못된 정보를 알고 있는거라면 정정해주시면 너무 감사하겠습니다 🙇‍♀️

image

@somsom13 somsom13 merged commit e132f22 into woowacourse:jaeyoung22 Sep 29, 2023
1 check failed
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