-
Notifications
You must be signed in to change notification settings - Fork 300
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단계] 아코(안석환) 미션 제출합니다. #564
Changes from 7 commits
bd7a892
adcd977
586d3cf
4d892d9
a2723e3
446546c
0691422
6976428
9608875
aa0ec01
1e99795
4c2165c
698b38b
0531ffc
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,35 @@ | ||
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 UserService { | ||
|
||
private final UserDao userDao; | ||
private final UserHistoryDao userHistoryDao; | ||
|
||
public AppUserService(final UserDao userDao, final UserHistoryDao userHistoryDao) { | ||
this.userDao = userDao; | ||
this.userHistoryDao = userHistoryDao; | ||
} | ||
|
||
@Override | ||
public User findById(Long id) { | ||
return userDao.findById(id); | ||
} | ||
|
||
@Override | ||
public void insert(User user) { | ||
userDao.insert(user); | ||
} | ||
|
||
@Override | ||
public void changePassword(Long id, String newPassword, String createBy) { | ||
final var user = findById(id); | ||
user.changePassword(newPassword); | ||
userDao.update(user); | ||
userHistoryDao.log(new UserHistory(user, createBy)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.techcourse.service; | ||
|
||
import com.techcourse.config.DataSourceConfig; | ||
import com.techcourse.domain.User; | ||
import com.techcourse.support.transaction.TransactionExecutor; | ||
|
||
public class TxUserService { | ||
|
||
private final UserService userService; | ||
private final TransactionExecutor transactionExecutor; | ||
|
||
public TxUserService(final UserService userService) { | ||
this.userService = userService; | ||
this.transactionExecutor = new TransactionExecutor(DataSourceConfig.getInstance()); | ||
} | ||
|
||
public User findById(final long id) { | ||
return userService.findById(id); | ||
} | ||
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. 조회는 트랜잭션이 없어도 괜찮을까요?! 스프링에서는 조회의 경우에도 이런 경우 DB 레벨에서 최적화가 가능해지는 것으로 알고 있어요. (DB가 읽기 전용 최적화를 지원한다면) 적용은 안해주셔도 좋으나, 읽기 전용 트랜잭션으로 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. 저도 리뷰를 받고 고민을 해보니 데이터를 조회하는 것도 결국에는 transaction의 격리수준을 보장 받아야 하기 때문에 데이터를 조회하는 것도 transsaction을 적용하겠습니다. 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.
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. 굿 제가 의도하신대로 잘 해주셨네요! |
||
|
||
public void insert(final User user) { | ||
transactionExecutor.execute(() -> userService.insert(user)); | ||
} | ||
|
||
public void changePassword(final long id, final String newPassword, final String createBy) { | ||
transactionExecutor.execute(() -> userService.changePassword(id, newPassword, createBy)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,12 @@ | ||
package com.techcourse.service; | ||
|
||
import com.techcourse.config.DataSourceConfig; | ||
import com.techcourse.dao.UserDao; | ||
import com.techcourse.dao.UserHistoryDao; | ||
import com.techcourse.domain.User; | ||
import com.techcourse.domain.UserHistory; | ||
import org.springframework.jdbc.exception.DataAccessException; | ||
import org.springframework.jdbc.exception.RollbackFailException; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
public interface UserService { | ||
|
||
public class UserService { | ||
User findById(final Long id); | ||
|
||
private final UserDao userDao; | ||
private final UserHistoryDao userHistoryDao; | ||
void insert(final User user); | ||
|
||
public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao) { | ||
this.userDao = userDao; | ||
this.userHistoryDao = userHistoryDao; | ||
} | ||
|
||
public User findById(final long id) { | ||
return userDao.findById(id); | ||
} | ||
|
||
public void insert(final User user) { | ||
userDao.insert(user); | ||
} | ||
|
||
public void changePassword(final long id, final String newPassword, final String createBy) throws SQLException { | ||
final DataSource dataSource = DataSourceConfig.getInstance(); | ||
final Connection connection = dataSource.getConnection(); | ||
try { | ||
connection.setAutoCommit(false); | ||
final var user = findById(id); | ||
user.changePassword(newPassword); | ||
userDao.update(connection, user); | ||
userHistoryDao.log(connection, new UserHistory(user, createBy)); | ||
connection.commit(); | ||
} catch (SQLException e) { | ||
rollback(connection); | ||
} finally { | ||
connection.close(); | ||
} | ||
} | ||
|
||
private static void rollback(Connection connection) { | ||
try { | ||
connection.rollback(); | ||
throw new DataAccessException("데이터에 접근할 수 없습니다."); | ||
} catch (SQLException exception) { | ||
throw new RollbackFailException("롤백을 실패했습니다."); | ||
} | ||
} | ||
void changePassword(final Long id, final String newPassword, final String createBy); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.techcourse.support.transaction; | ||
|
||
import java.sql.SQLException; | ||
|
||
@FunctionalInterface | ||
public interface ServiceLogicExecutor { | ||
|
||
void execute() throws SQLException; | ||
} | ||
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. Runnable을 사용하지 않고 따로 ServiceLogicExecutor를 사용해주신 이유가 있을까요? 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. 구현을 할 당시에 Runnable이 떠오르지 않았어서 구현을 했었는데 Runnable로 처리가 가능할것 같네요! 이 부분 수정하겠습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package com.techcourse.support.transaction; | ||
|
||
import org.springframework.jdbc.datasource.DataSourceUtils; | ||
import org.springframework.jdbc.exception.DataAccessException; | ||
import org.springframework.jdbc.exception.RollbackFailException; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
|
||
public class TransactionExecutor { | ||
|
||
private final DataSource dataSource; | ||
|
||
public TransactionExecutor(DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public void execute(final ServiceLogicExecutor serviceLogicExecutor) { | ||
final Connection connection = DataSourceUtils.getConnection(dataSource); | ||
try { | ||
connection.setAutoCommit(false); | ||
serviceLogicExecutor.execute(); | ||
connection.commit(); | ||
} catch (SQLException e) { | ||
rollback(connection); | ||
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. 롤백은 SQLException이 발생할 때만 수행되어야 할까요? SQLException에 대해서만 rollback을 수행하면 어떤 문제가 생길 수 있을까요? 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. Runtime 시점에 예외를 처리하지 못할 것 같습니다. Runtim에도 예외가 발생할 수 있게 수정하겠습니다. |
||
} finally { | ||
DataSourceUtils.releaseConnection(connection, dataSource); | ||
} | ||
} | ||
|
||
private static void rollback(Connection connection) { | ||
try { | ||
connection.rollback(); | ||
throw new DataAccessException("데이터에 접근할 수 없습니다."); | ||
} catch (SQLException exception) { | ||
throw new RollbackFailException("롤백을 실패했습니다."); | ||
} | ||
} | ||
} |
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
인터페이스를 구현하고 있지 않네요!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.
이 부분 실수를 범했네요 수정하겠습니다!