-
Notifications
You must be signed in to change notification settings - Fork 379
[4단계 - Transaction synchronization 적용하기] 폰트(김영재) 미션 제출합니다. #1164
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: yeong0jae
Are you sure you want to change the base?
Conversation
Walkthrough이 변경사항은 명시적 Connection 매개변수 기반의 DAO 메서드를 제거하고 암시적 Connection 관리로 전환합니다. UserService를 구체적 클래스에서 인터페이스로 변경하고, AppUserService와 TxUserService를 도입하여 데이터 접근과 트랜잭션 관리를 분리합니다. JdbcTemplate과 DataSourceUtils를 수정하여 DataSourceUtils.getConnection()을 사용하도록 하고, TransactionSynchronizationManager에 ThreadLocal 기반 리소스 관리 로직을 구현합니다. 이를 통해 트랜잭션 중인 Connection의 조기 종료를 방지합니다. Pre-merge checks❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java (1)
15-28
: getConnection() 설계에 실제 문제가 있습니다. 원본 리뷰 의견이 정확합니다.현재 구현의 문제점:
트랜잭션 컨텍스트에서는 정상 작동:
TxUserService
:getConnection()
→ 작업 → finally에서unbindResource()
→releaseConnection()
순서로 올바르게 정리비트랜잭션 컨텍스트에서는 누수 발생:
JdbcTemplate
(line 56, 88):getConnection()
호출 후releaseConnection()
만 호출,unbindResource()
미호출releaseConnection()
은 바인딩된 Connection을 닫지 않으므로 Connection이 ThreadLocal에 남음- 다음 Thread가 ThreadLocal을 재사용할 때 이전 Connection 참조 유지 → Connection 누수 + ThreadLocal 메모리 누수
문제의 근본 원인:
getConnection()
이 항상 무조건 Connection을 바인딩하지만, 모든 호출자가 트랜잭션 종료 시unbindResource()
를 호출하는 것은 아닙니다.개선 방향:
getConnection()
은 이미 바인딩된 Connection이 있을 때만 사용하고, 트랜잭션 외부에서는 직접dataSource.getConnection()
을 사용하도록 설계- 또는
getConnection()
이 트랜잭션 컨텍스트 여부를 확인하여 필요할 때만 바인딩하도록 수정app/src/test/java/com/techcourse/service/AppUserServiceTest.java (1)
31-44
: 식별자 고정 사용(id=1L)의 취약성id=1L을 가정하면 팝퓰레이터/시퀀스 설정에 따라 깨질 수 있습니다. 계정으로 조회해 id를 얻거나 insert 결과를 통해 실제 id를 사용하도록 바꾸면 테스트가 더 견고해집니다.
코딩 가이드라인 기준
🧹 Nitpick comments (12)
jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java (2)
56-67
: 예외 처리 구조를 단순화할 수 있을 것 같습니다.Lines 59-61에서
DataAccessException
을 catch해서 다시 throw하고 있는데, 이 부분이 정말 필요한지 고려해보세요.질문:
DataAccessException
은 어떤 종류의 예외인가요? (checked vs unchecked)- 만약 unchecked 예외라면, catch하지 않아도 자동으로 전파되지 않나요?
- Line 59-61의 catch 블록을 제거하면 어떻게 될까요?
힌트:
try { return queryForObject(conn, sql, rowMapper, setter); } catch (Exception e) { // DataAccessException도 Exception이므로 여기서 처리됨 log.error("SQL execution failed: {}", sql, e); throw new DataAccessException(e); } finally { DataSourceUtils.releaseConnection(conn, dataSource); }현재 구조에서는 DataAccessException이 발생하면:
- Line 59에서 catch되어 line 60에서 rethrow
- 하지만 DataAccessException을 Exception으로 감싸서 던지는 line 63은 실행되지 않음
이 구조의 의도가 무엇인지 다시 생각해보세요.
88-99
: Connection 관리 방식의 일관성을 고려해보셨나요?이 메서드는 DataSourceUtils를 통해 Connection을 관리하지만, 동일한 클래스 내의 다른 오버로드된 메서드들(line 35-37의 update, line 69-85의 queryForObject)은 Connection을 파라미터로 받아서 직접 관리합니다.
고려할 점:
- 두 가지 Connection 관리 방식이 혼재되어 있을 때, 호출하는 쪽에서 어떤 메서드를 선택해야 하는지 명확한가요?
- Connection을 파라미터로 받는 메서드들은 어떤 상황에서 사용되어야 할까요?
- 이러한 메서드들이 public으로 노출되어 있는 것이 적절한가요, 아니면 package-private이나 private으로 제한하는 것이 더 나을까요?
힌트:
- Connection을 직접 받는 메서드들은 트랜잭션 컨텍스트 내에서 이미 관리되는 Connection을 사용하기 위한 것으로 보입니다.
- 그렇다면 이들의 접근 제한자를 조정하거나, 명확한 네이밍으로 용도를 구분하는 것이 어떨까요?
app/src/main/java/com/techcourse/service/TxUserService.java (3)
28-44
: 중첩 try-catch로 인한 들여쓰기 깊이 초과규칙 1(메서드 들여쓰기 depth 1) 위반 가능성이 큽니다. 예외 흐름(시작/성공/실패)을 작은 메서드로 분리하거나 가드 클로즈로 납작하게 만들면 의도가 더 또렷해져요.
- 예: begin/commit/rollback 책임 분리, 예외 매핑 분리.
코딩 가이드라인 기준
28-28
: 원시값 포장 검토: id, newPassword, createdBy규칙 3에 따라 UserId, Password, Operator(또는 CreatedBy) 등 값 객체로 포장하면 유효성·의미가 응집됩니다. 비밀번호 정책 검증도 자연스럽게 해당 타입으로 이동할 수 있어요.
코딩 가이드라인 기준
42-46
: 예외 매핑 메시지와 책임 경계DataAccessException 메시지가 “무엇이 실패했는가”보다 “왜 실패했는가(상태/전이)”를 드러내면 디버깅에 유리합니다. 또한 트랜잭션 관리 계층(TxUserService)에서만 트랜잭션 관련 예외를 감싸고, 도메인/DAO 예외는 원인 그대로 유지하는지 점검해보세요.
코딩 가이드라인 기준app/src/test/java/com/techcourse/service/AppUserServiceTest.java (4)
21-29
: 테스트 데이터 초기화의 결정성 확보DatabasePopulatorUtils.execute 호출과 수동 insert 조합이 매 테스트마다 동일한 초기 상태를 보장하는지 확인이 필요합니다. 공유 DataSource 싱글턴에서 테스트 간 상태가 새고 있지 않은지도요.
- 각 테스트 시작 시 테이블 정리 또는 트랜잭션 롤백 전략을 고려해보셨나요?
코딩 가이드라인 기준
38-39
: 용어 일관성: createdBy vs createBy프로덕션 코드의 파라미터는 createdBy인데, 테스트 로컬 변수는 createBy입니다. 용어를 통일하면 의도가 더 명확해져요.
코딩 가이드라인 기준
43-43
: 게터 기반 검증 대신 행위 검증 고려규칙 9(Tell, Don’t Ask) 관점에서 비밀번호 검증을 상태 노출(getPassword) 대신 도메인 행위(예: 비밀번호 일치 여부)로 검증해볼 수 있을까요? 테스트도 행위 중심으로 바뀝니다.
코딩 가이드라인 기준
46-62
: 롤백 테스트에 대한 추가 단언과 리소스 해제 검증현재 예외 발생과 기존 비밀번호 유지까지 검증은 좋습니다. 여기에 다음을 고려해보세요.
- user_history 레코드 미삽입 단언(중복 쓰기 방지 확인).
- 테스트 종료 시 ThreadLocal 바인딩 잔존 여부 확인(비트랜잭션 findById 호출이 커넥션을 남기지 않는지).
코딩 가이드라인 기준app/src/main/java/com/techcourse/service/AppUserService.java (2)
18-22
: findById 재사용 고려changePassword 내부에서 다시 DAO를 직접 호출하기보다, 동일 클래스의 findById를 재사용하면 의도 표현과 중복 제거에 유리합니다.
코딩 가이드라인 기준
23-29
: 도메인 이벤트/행위로의 위임을 검토
- 원시값 포장(Password, Operator)으로 정책·검증 응집.
- User가 “비밀번호 변경됨” 이력을 생성/기록하도록 위임하면(Tell, Don’t Ask) 디미터 법칙과 규칙 9에 더 부합합니다.
코딩 가이드라인 기준app/src/main/java/com/techcourse/service/UserService.java (1)
5-9
: 인터페이스 전환으로 결합도 하락 — 방향 좋습니다표면이 단순해져 테스트 대역 교체가 쉬워졌습니다. 다만 다음도 고려해보세요.
- findById의 실패 케이스 계약(Optional/예외) 명시.
- 원시값 포장 타입 도입으로 의도 강화(특히 Password, UserId, Operator).
코딩 가이드라인 기준
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
app/src/main/java/com/techcourse/dao/UserDao.java
(0 hunks)app/src/main/java/com/techcourse/dao/UserHistoryDao.java
(0 hunks)app/src/main/java/com/techcourse/service/AppUserService.java
(1 hunks)app/src/main/java/com/techcourse/service/TxUserService.java
(1 hunks)app/src/main/java/com/techcourse/service/UserService.java
(1 hunks)app/src/test/java/com/techcourse/service/AppUserServiceTest.java
(3 hunks)app/src/test/java/com/techcourse/service/MockUserHistoryDao.java
(0 hunks)jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java
(3 hunks)jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java
(1 hunks)jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java
(2 hunks)
💤 Files with no reviewable changes (3)
- app/src/main/java/com/techcourse/dao/UserHistoryDao.java
- app/src/test/java/com/techcourse/service/MockUserHistoryDao.java
- app/src/main/java/com/techcourse/dao/UserDao.java
🧰 Additional context used
📓 Path-based instructions (1)
**/*.java
⚙️ CodeRabbit configuration file
**/*.java
: ## 🎯 코드 품질 중심 리뷰 가이드라인이 리뷰는 코드 품질과 객체지향 원칙에 집중합니다.
미션 달성 여부가 아닌, 코드 설계와 품질 개선에 대한 피드백을 한글로 제공해주세요.📚 학습 원칙
- 직접 코드를 제공하지 마세요 (학습자가 명시적으로 요청하는 경우 제외)
- 문제 해결 과정을 안내하되, 정답을 바로 알려주지 마세요
- 작은 단계로 문제를 분해하여 접근하도록 도와주세요
💡 피드백 방법
- 유도 질문 활용: "만약 ~라면 어떻게 될까요?", "~를 고려해보셨나요?"
- 힌트 제공: 방향은 제시하되, 구체적인 구현은 학습자가 하도록
- 다양한 접근법 제시: 한 가지 해결책이 아닌 여러 가능성을 제안
- 왜?에 집중: 단순히 무엇이 잘못되었는지보다 왜 그런지 이해하도록
⚡ 객체지향 생활 체조 원칙 검토
다음은 객체지향 생활 체조(Object Calisthenics) 9가지 원칙입니다.
위반 시 학습 효과를 위해 반드시 피드백을 제공하되, 왜 이 원칙이 중요한지 설명해주세요:규칙 1: 한 메서드에 오직 한 단계의 들여쓰기만
- 들여쓰기 depth 최대 1 (중첩 제어구조 금지)
- 📖 이유: 메서드 복잡도 감소, 단일 책임 원칙 강화
- 💡 힌트: "이 부분을 별도 메서드로 추출하면 어떨까요?"
규칙 2: else 예약어 금지
- else, switch/case 사용 금지
- 📖 이유: 복잡한 분기 제거, 명확한 코드 흐름
- 💡 힌트: "early return이나 가드 클로즈 패턴을 고려해보세요"
규칙 3: 모든 원시값과 문자열 포장
- 원시 타입과 String을 객체로 포장
- 📖 이유: 도메인 개념 명확화, 비즈니스 로직 응집
- 💡 예시:
int port
→Port port
,String name
→Name name
규칙 4: 한 줄에 점 하나만 (디미터 법칙)
- 메서드 체이닝 제한
- 📖 이유: 결합도 감소, 캡슐화 향상
- 💡 나쁜 예:
request.getUri().getPath().substring()
- 💡 좋은 예:
request.extractPath()
규칙 5: 축약 금지
- 명확한 이름 사용 (축약어 금지)
- 📖 이유: 코드 가독성, 의도 명확화
- 💡 예시:
req
→request
,calcAmt
→calculateAmount
규칙 6: 모든 엔티티를 작게 유지
- 클래스 50줄, 메서드 10줄 이하
- 📖 이유: 단일 책임, 이해와 테스트 용이성
- 💡 힌트: "이 클래스가 너무 많은 일을 하고 있지 않나요?"
규칙 7: 인스턴스 변수 3개 이하
- 클래스당 최대 3개의 인스턴스 변수
- 📖 이유: 높은 응집도, 단일 책임 유지
- 💡 힌트: "관련 필드들을 별도 객체로 묶을 수 있을까요?"
규칙 8: 일급 컬렉션 사용
- 컬렉션을 감싸는 클래스 사용
- 📖 이유: 컬렉션 로직 캡슐화, 불변성 보장
- 💡 예시:
List<HttpHeader>
→HttpHeaders
클래스규칙 9: 게터/세터/프로퍼티 금지
- Tell, Don't Ask 원칙 준수
- 📖 이유: 진정한 캡슐화, 객체 자율성
- 💡 나쁜 예:
if (user.getPassword().equals(input))
- 💡 좋은 예:
if (user.authenticate(input))
🎯 추가 프로그래밍 요구사항
코드 스타일
- Java Style Guide 준수
- 3항 연산자 사용 금지
테스트 및 구조
- **모든 기능 T...
Files:
jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java
app/src/main/java/com/techcourse/service/AppUserService.java
app/src/main/java/com/techcourse/service/TxUserService.java
jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java
jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java
app/src/test/java/com/techcourse/service/AppUserServiceTest.java
app/src/main/java/com/techcourse/service/UserService.java
🧬 Code graph analysis (6)
jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java (1)
jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java (1)
TransactionSynchronizationManager
(8-42)
app/src/main/java/com/techcourse/service/AppUserService.java (1)
app/src/main/java/com/techcourse/dao/UserHistoryDao.java (1)
UserHistoryDao
(8-31)
app/src/main/java/com/techcourse/service/TxUserService.java (2)
jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java (1)
DataSourceUtils
(11-49)jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java (1)
TransactionSynchronizationManager
(8-42)
jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java (1)
jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java (1)
DataSourceUtils
(11-49)
app/src/test/java/com/techcourse/service/AppUserServiceTest.java (1)
app/src/main/java/com/techcourse/config/DataSourceConfig.java (1)
DataSourceConfig
(7-27)
app/src/main/java/com/techcourse/service/UserService.java (1)
study/src/test/java/aop/stage1/UserService.java (1)
UserService
(9-36)
🔇 Additional comments (6)
jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java (2)
8-12
: ThreadLocal 기반 리소스 관리 패턴이 잘 구현되었습니다.유틸리티 클래스로서 적절한 설계(abstract 클래스 + private 생성자)를 따르고 있고, ThreadLocal을 활용하여 스레드별 Connection 관리를 구현한 점이 좋습니다.
31-41
: ThreadLocal 정리 로직이 잘 구현되었습니다.Map이 비었을 때
resources.remove()
를 호출하여 ThreadLocal을 정리하는 것은 메모리 누수를 방지하는 좋은 패턴입니다.jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java (1)
30-48
: releaseConnection의 바운드 Connection 체크 로직 자체는 잘 구현되었습니다.null 체크(lines 31-33)와 바인딩된 Connection인지 확인하는 로직(lines 36-40)이 적절합니다. 다만 이 메서드가 제대로 동작하려면 위의
getConnection
메서드의 바인딩 전략이 수정되어야 합니다.app/src/main/java/com/techcourse/service/TxUserService.java (2)
12-20
: 트랜잭션 경계 분리 자체는 좋습니다도메인 로직(AppUserService)과 트랜잭션 경계를 TxUserService로 분리한 방향은 응집도/확장성 측면에서 바람직합니다.
22-25
: 내부 DAO 레이어의 커넥션 바인딩 불일치 패턴 확인 필요검증 결과, 귀사의 우려가 기술적으로 타당합니다. 문제 분석:
- 쓰기 경로 (
changePassword
, 라인 47-48):DataSourceUtils.getConnection()
→ 트랜잭션 관리 → 명시적unbindResource()
→releaseConnection()
- 읽기 경로 (
findById
):JdbcTemplate
사용 →DataSourceUtils.getConnection()
(ThreadLocal 바인드) →releaseConnection()
만 호출 → unbind 없음
DataSourceUtils.releaseConnection()
구현상 이미 바인딩된 커넥션은 close하지 않고(라인 37-39), 명시적unbindResource()
호출 없이는 ThreadLocal에서 해제되지 않습니다.결과:
findById()
가 트랜잭션 경계 외부에서 호출될 때 JdbcTemplate이 바인딩한 커넥션이 ThreadLocal에 남아 있을 수 있습니다.권장 개선:
- JdbcTemplate의 finally 블록에서도
unbindResource()
를 추가하거나findById()
도changePassword()
처럼 명시적 트랜잭션 경계를 관리하거나- 전체 서비스 레이어에서 일관된 트랜잭션 관리 전략(@transactional 통일 등)을 적용
이를 통해 읽기/쓰기 경로 간 리소스 관리 일관성을 확보할 수 있습니다.
app/src/main/java/com/techcourse/service/AppUserService.java (1)
8-16
: 역할 분리와 의존성 최소화 좋습니다DAO 두 개만 주입받는 얇은 서비스로 응집도가 높습니다. 테스트 용이성도 올라갑니다.
public void changePassword(final long id, final String newPassword, final String createdBy) { | ||
Connection connection = DataSourceUtils.getConnection(dataSource); | ||
try { | ||
connection.setAutoCommit(false); | ||
|
||
try { | ||
userService.changePassword(id, newPassword, createdBy); | ||
connection.commit(); | ||
} catch (Exception e) { | ||
try { | ||
connection.rollback(); | ||
} catch (SQLException rollbackEx) { | ||
e.addSuppressed(rollbackEx); | ||
} | ||
throw new DataAccessException("Failed to change password for user id: " + id, e); | ||
} | ||
} catch (SQLException e) { | ||
throw new DataAccessException("Failed to manage transaction", e); | ||
} finally { | ||
TransactionSynchronizationManager.unbindResource(dataSource); | ||
DataSourceUtils.releaseConnection(connection, dataSource); | ||
} |
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.
트랜잭션 소유권(ownership)과 중첩 트랜잭션 참여(propagation) 미정의
현재 구현은 다음 두 가지 위험이 있습니다.
- 이미 바인딩된 커넥션이 있는 경우에도 setAutoCommit(false)·commit/rollback·unbind를 무조건 수행합니다. 외부(상위) 트랜잭션이 존재하면 소유하지 않은 리소스를 해제하여 흐름을 깨뜨릴 수 있어요.
- finally에서 항상 unbindResource 호출 → 자신이 시작하지 않은 바인딩까지 해제할 수 있습니다.
질문/힌트
- “내가 트랜잭션을 시작했는가?”를 표시하는 플래그(참여 여부)로 commit/rollback 및 unbind 실행 조건을 분기하면 어떨까요?
- 전파 속성(필요 시 REQUIRED, REQUIRES_NEW 등)과 ‘참여/비참여’ 개념을 최소한의 형태로라도 명시해볼 수 있을까요?
- 커넥션이 이미 바인딩되어 있다면 setAutoCommit 상태 변경을 피해야 하지 않을까요?
코딩 가이드라인 기준
🤖 Prompt for AI Agents
In app/src/main/java/com/techcourse/service/TxUserService.java around lines 28
to 49, the method unconditionally takes ownership of the connection and
transaction lifecycle even when a connection is already bound by an external
transaction; change it to detect whether a connection/transaction is already
bound and only manage autoCommit/commit/rollback/unbind when this method
actually started the transaction. Concretely: check
TransactionSynchronizationManager.hasResource(dataSource) (or equivalent) before
calling setAutoCommit(false) and mark a boolean "startedTx"; perform
commit/rollback and TransactionSynchronizationManager.unbindResource(dataSource)
only if startedTx is true (and avoid changing autoCommit for bound connections);
always release the connection via DataSourceUtils.releaseConnection in finally.
This implements minimal propagation semantics (participate if bound, start new
otherwise) and prevents unbinding resources you don't own.
public static void bindResource(DataSource key, Connection value) { | ||
Map<DataSource, Connection> map = resources.get(); | ||
if (map == null) { | ||
map = new HashMap<>(); | ||
resources.set(map); | ||
} | ||
map.put(key, value); | ||
} |
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.
중복 바인딩에 대한 처리를 고려해보셨나요?
현재 bindResource
메서드는 이미 바인딩된 DataSource에 대해 새로운 Connection을 덮어쓸 수 있습니다. 만약 동일한 DataSource에 대해 중복으로 bindResource가 호출된다면 어떤 일이 발생할까요?
고려할 점:
- 이전에 바인딩된 Connection이 제대로 정리되지 않은 채 새로운 Connection으로 교체되면 어떤 문제가 발생할 수 있을까요?
- 중복 바인딩을 감지하고 예외를 던지거나, 로깅을 추가하는 것이 더 안전하지 않을까요?
힌트:
if (map.containsKey(key)) {
// 이미 바인딩된 경우 처리
}
🤖 Prompt for AI Agents
In
jdbc/src/main/java/com/interface21/transaction/support/TransactionSynchronizationManager.java
around lines 22 to 29, bindResource currently overwrites an existing Connection
for the same DataSource without handling the previous binding; update the method
to detect duplicate binds (e.g. map.containsKey(key)) and handle them by either
throwing an IllegalStateException with a clear message or logging a warning
before replacing, and if replacing ensure the previous Connection is cleaned
up/closed or explicitly left for caller responsibility; implement the chosen
behavior consistently and document it in the method's Javadoc.
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.
폰병장님 오늘도 배워갑니다.
궁금한 점 몇 개만 달았습니다. 단결 🫡
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
|
||
public class TxUserService implements UserService { |
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.
필드로 UserService 들고있는 이상 impl 할 필요없을 것 같은데, 어떻게 생각하시나요?
@Override | ||
public void changePassword(final long id, final String newPassword, final String createdBy) { | ||
Connection connection = DataSourceUtils.getConnection(dataSource); | ||
try { |
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.
Connection
을 필드로 가지고 있는 객체가 나오면 좋을 것 같은데, 어떻게 생각하시나요?
이름은 Transaction
이 될 것 같아요.
해당 로직이 조금 추상화 된다면 좋을 것 같아서요. 폰병장님의 생각이 궁금하네요.
|
||
public static Connection unbindResource(DataSource key) { | ||
return null; | ||
Map<DataSource, Connection> map = resources.get(); |
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.
void
여도 될 것 같아요
throw new DataAccessException("Failed to manage transaction", e); | ||
} finally { | ||
TransactionSynchronizationManager.unbindResource(dataSource); | ||
DataSourceUtils.releaseConnection(connection, dataSource); |
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.
unbindResource
메서드 releaseConnection
에서 호출해도 되지 않나요?
connection, dataSource 처리 지점이 두 곳이라 추적이 어려울 것 같아요.
안녕하세요 말론. 이제 마지막 미션이네요.
고생하셨습니다.
4단계 미션 구현 해봤습니다.
변경 사항은 다음과 같습니다.