-
Notifications
You must be signed in to change notification settings - Fork 379
[4단계 - Transaction synchronization 적용하기] 하루(구은선) 미션 제출합니다. #1216
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
Changes from all commits
6417b60
8221abd
965c79b
601fcec
5b63c9f
e86949d
11f9bc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| package com.techcourse.service; | ||
|
|
||
| import com.techcourse.dao.UserDao; | ||
| import com.techcourse.dao.UserHistoryDao; | ||
| import com.techcourse.domain.User; | ||
| import com.techcourse.domain.UserHistory; | ||
|
|
||
| public class AppUserService implements UserServiceInterface { | ||
|
|
||
| private final UserDao userDao; | ||
| private final UserHistoryDao userHistoryDao; | ||
|
|
||
| public AppUserService(UserDao userDao, UserHistoryDao userHistoryDao) { | ||
| this.userDao = userDao; | ||
| this.userHistoryDao = userHistoryDao; | ||
| } | ||
|
|
||
| @Override | ||
| public User findById(long id) { | ||
| return userDao.findById(id) | ||
| .orElseThrow(() -> new IllegalArgumentException("사용자 정보가 존재하지 않습니다.")); | ||
| } | ||
|
|
||
| @Override | ||
| public void save(User user) { | ||
| userDao.insert(user); | ||
| } | ||
|
|
||
| @Override | ||
| public void changePassword(long id, String newPassword, String createdBy) { | ||
| final var user = userDao.findById(id) | ||
| .orElseThrow(() -> new IllegalArgumentException("사용자 정보가 존재하지 않습니다.")); | ||
| user.changePassword(newPassword); | ||
| userDao.update(user); | ||
| userHistoryDao.log(new UserHistory(user, createdBy)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| package com.techcourse.service; | ||
|
|
||
| import com.interface21.dao.DataAccessException; | ||
| import com.interface21.jdbc.core.TransactionCallback; | ||
| import com.interface21.jdbc.datasource.DataSourceUtils; | ||
| import com.techcourse.config.DataSourceConfig; | ||
| import com.techcourse.domain.User; | ||
| import java.sql.Connection; | ||
| import java.sql.SQLException; | ||
| import javax.sql.DataSource; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| public class TxUserService implements UserServiceInterface { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(TxUserService.class); | ||
| private final UserServiceInterface userServiceInterface; | ||
|
|
||
| public TxUserService(UserServiceInterface userServiceInterface) { | ||
| this.userServiceInterface = userServiceInterface; | ||
| } | ||
|
|
||
| // override 대상인 메서드는 userService의 메서드를 그대로 위임(delegate)한다. | ||
| @Override | ||
| public void changePassword(final long id, final String newPassword, final String createdBy) { | ||
| executeTransaction(() -> userServiceInterface.changePassword(id, newPassword, createdBy)); | ||
| } | ||
|
|
||
| @Override | ||
| public void save(User user) { | ||
| executeTransaction(() -> userServiceInterface.save(user)); | ||
| } | ||
|
|
||
| @Override | ||
| public User findById(long id) { | ||
| return executeTransaction(() -> userServiceInterface.findById(id)); | ||
| } | ||
|
|
||
| private void executeTransaction(Runnable runnable) { | ||
| executeTransaction(() -> { | ||
| runnable.run(); | ||
| return null; | ||
| }); | ||
| } | ||
|
|
||
| private <T> T executeTransaction(TransactionCallback<T> transactionCallback) { | ||
| DataSource dataSource = DataSourceConfig.getInstance(); | ||
| Connection connection = null; | ||
| try { | ||
| connection = DataSourceUtils.getConnection(dataSource); | ||
| connection.setAutoCommit(false); | ||
| T result = transactionCallback.doInTransaction(); | ||
| connection.commit(); | ||
| return result; | ||
| } catch (SQLException e) { | ||
| if (connection != null) { | ||
| try { | ||
| connection.rollback(); | ||
| } catch (SQLException ex) { | ||
| log.error("Rollback failed", ex); | ||
| throw new DataAccessException("Rollback failed"); | ||
| } | ||
| } | ||
| throw new DataAccessException(e); | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확실히 AI 리뷰와 마찬가지로 데이터 접근 예외만 DataAccessException로 매핑하고, 도메인 관련 예외는 기존 예외 그대로 외부에 전파되면 좋을 것 같습니다!
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 동의해요! 반영해서 수정했습니다 |
||
| } catch (RuntimeException e) { | ||
| if (connection != null) { | ||
| try { | ||
| connection.rollback(); | ||
| } catch (SQLException ex) { | ||
| log.error("Rollback failed", ex); | ||
| throw new DataAccessException("Rollback failed"); | ||
| } | ||
| } | ||
| throw e; | ||
| } finally { | ||
| if (connection != null) { | ||
| try { | ||
| DataSourceUtils.releaseConnection(connection, dataSource); | ||
| } catch (Exception ex) { | ||
| log.error("Failed to release connection or unbind resource", ex); | ||
| } | ||
| } | ||
|
Comment on lines
+76
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 트랜잭션 종료 후 커넥션 해제가 이뤄지지 않는 문제를 확인해주세요
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.techcourse.service; | ||
|
|
||
| import com.techcourse.domain.User; | ||
|
|
||
| public interface UserServiceInterface { | ||
| User findById(final long id); | ||
|
|
||
| void save(final User user); | ||
|
|
||
| void changePassword(final long id, final String newPassword, final String createdBy); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.interface21.jdbc.core; | ||
|
|
||
| @FunctionalInterface | ||
| public interface TransactionCallback<T> { | ||
|
|
||
| T doInTransaction(); | ||
| } |
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.
함수 인터페이스를 통해 트랜잭션 관련 코드의 중복을 없앤 점 좋습니다! 👍