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 라이브러리 구현하기 - 4단계] 에버(손채영) 미션 제출합니다. #923

Open
wants to merge 14 commits into
base: helenason
Choose a base branch
from

Conversation

helenason
Copy link
Member

몰리 안녕하세요 ~~~~

벌써 마지막 미션의 마지막 단계네요!

요구사항은 모두 만족시켰는데, 제 방식이 옳은지 확신이 서지 않아요.

편하게 의견 남겨주세요!

감사합니다.

@helenason helenason self-assigned this Oct 14, 2024
Copy link

@jminkkk jminkkk left a comment

Choose a reason for hiding this comment

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

안녕하세요 에버!
이번 단계도 미션 잘 진행해주셨네요 😁

몇가지 코멘트 남겨보았으니 이번 단계도 파이팅입니다 🔥

throw new DataAccessException(e);
} finally {
DataSourceUtils.releaseConnection(conn, dataSource);
TransactionSynchronizationManager.unbindResource(dataSource);
Copy link

Choose a reason for hiding this comment

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

DataSourceUtils.getConnection로 Connection을 가져올 때 내부에서는 TransactionSynchronizationManager.bindResource를 호출해주도록 하고 있는데요
unbindResourceDataSourceUtils 내부에 위치시키지 않은 이유가 궁금해요!

Copy link
Member Author

Choose a reason for hiding this comment

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

사실 저도 그 부분을 고려해 DataSourceUtils 내부에 위치시킬까 하였는데요. 고민하다가 일단은 기존 작성되어있는 코드를 따르기로 했었습니다. 하지만 지금 코드를 다시 보니, 내부에 위치시키는 게 맞아보이네요!

}

public static void bindResource(DataSource key, Connection value) {
if (resources.get() == null) {
Map<DataSource, Connection> map = new HashMap<>();
Copy link

Choose a reason for hiding this comment

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

ThreadLocal에는 withInitial 라는 유틸리티 메서드를 제공하고 있다는 사실...!

Copy link
Member Author

Choose a reason for hiding this comment

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

헉 너무 좋은데요? 👍

Comment on lines +48 to +63
@DisplayName("실행을 실패할 경우 롤백한다.")
@Test
void should_rollbackLogic_when_manageFail() throws SQLException {
// given
when(dataSource.getConnection()).thenThrow(SQLException.class);

List<String> test = new ArrayList<>();

// when & then
assertThatThrownBy(() -> {
transactionManager.manage(conn -> {
test.add("new");
});
}).isInstanceOf(CannotGetJdbcConnectionException.class);
assertThat(test).hasSize(0);
}
Copy link

Choose a reason for hiding this comment

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

꼼꼼한 테스트 좋네요 굿 👍👍

Comment on lines 16 to 19
if (resources.get() == null) {
return null;
}
return resources.get().get(key);
Copy link

Choose a reason for hiding this comment

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

resources.get()에 key가 존재하지 않을 경우에는 NPE가 터질 일은 없을까요...??

Copy link
Member Author

Choose a reason for hiding this comment

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

사용하는 쪽에서 null 검증을 해주고 있기 때문에 문제 없다고 생각하긴 했지만 안일했던 것 같네요. @Nullable 어노테이션으로 명시함으로써 NPE 발생 가능성을 줄여보았습니다. 혹시 더 좋은 방법이 있을까요오 🧐

Copy link

Choose a reason for hiding this comment

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

앗 제가 잘못 리뷰드렸네요 ㅎㅎ...
map에 해당하는 key가 없는 경우 npe가 아니라 null을 반환하네요. 제가 착각했습니다...ㅎㅎ

@Nullable 최고에요 👍👍

@@ -1,10 +1,9 @@
package com.techcourse.service;
package com.techcourse.service.support;
Copy link

Choose a reason for hiding this comment

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

support 패키지 안으로 이동하신 이유가 궁금해요!
main 패키지 하위에도 support가 있어서 자칫 main.~.support에 대한 테스트로 오해할 수도 있을 것 같은데 에버의 생각이 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

저의 원래 의도는 jdbc 모듈 테스트 패키지 내부의 support와 같은 패키지였습니다! 하지만 몰리의 의견대로 오해의 소지가 있겠네요! 테스트를 돕는 도구이니 helper 정도로 네이밍해볼까 합니다 ㅎㅎ

@helenason
Copy link
Member Author

몰리~~~

리뷰 반영하고 학습테스트 추가해서 리뷰 재요청 드립니다!

이번 학습테스트는 구현에 집중했던 것 같아요.
그래서 혹시 학습테스트 진행하시면서 학습했던 키워드 있다면 던져주시면 감사하겠습니다!

이번 리뷰도 잘 부탁드려요 :)

Copy link

@jminkkk jminkkk 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 +26 to +27
if (!target.getClass().getMethod(method.getName(), method.getParameterTypes())
.isAnnotationPresent(Transactional.class)) {
Copy link

Choose a reason for hiding this comment

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

Suggested change
if (!target.getClass().getMethod(method.getName(), method.getParameterTypes())
.isAnnotationPresent(Transactional.class)) {
if (!method.isAnnotationPresent(Transactional.class)) {

Transactional 어노테이션이 없는 경우를 판단하는 로직 같아요!
Method 클래스의 isAnnotationPresent를 사용하면 가독성이 좋아질 것 같은데 어떤가요?ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

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

실제 구현체(target)가 가지고 있는 method에서 어노테이션 검증을 하는 방식이 아닌, 파라미터로 받은 method를 통해 검증하게 되면 interface의 메서드를 검증하게 되어 @Transactional이 없다는 결과가 출력돼요! 따라서 위와 같이 target 구현체의 method를 사용하게 되었습니다 :)

return ret;
} catch (Exception e) {
platformTransactionManager.rollback(transactionStatus);
log.info("transaction roll back: {}", invocation.getMethod().getName());
Copy link

Choose a reason for hiding this comment

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

로그 굿 👍👍👍
사소하지만 invocation.getMethod().getName()가 여러번 사용되는 것 같아, 변수로 추출해도 좋을 것 같네요 ㅎㅎ

@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
Copy link

Choose a reason for hiding this comment

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

setProxyTargetClass() 설정이 false, true 인 경우 각각 어떤 상황이 벌어지나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

proxyTragetClass 설정이 true인 경우 CGLIB, false인 경우 JDK Proxy를 사용하는 것으로 알고 있습니다!

Comment on lines 16 to 19
if (resources.get() == null) {
return null;
}
return resources.get().get(key);
Copy link

Choose a reason for hiding this comment

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

앗 제가 잘못 리뷰드렸네요 ㅎㅎ...
map에 해당하는 key가 없는 경우 npe가 아니라 null을 반환하네요. 제가 착각했습니다...ㅎㅎ

@Nullable 최고에요 👍👍

@helenason
Copy link
Member Author

몰리 마지막까지 감사했습니다!

남은 기간 파이팅이에요 👊

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