Skip to content

Commit 43fef41

Browse files
authored
[4단계 - Transaction synchronization 적용하기] 링크(손준형) 미션 제출합니다. (#1215)
* feat: UserService 인터페이스 생성 * feat: AppUserService 구현 * feat: 트랜잭션 서비스 추상화 * test: UserServiceTest를 서비스 추상화 패턴에 맞게 수정 * refactor: DataSourceUtils에서 자동 바인딩 제거 * refactor: TxUserService에서 Connection 명시적 바인딩 * refactor: Connection Pool 재사용을 위해 autoCommit 상태 복원 * refactor: unbind resource * refactor: change originalAutoCommit init
1 parent cc41b22 commit 43fef41

File tree

5 files changed

+121
-74
lines changed

5 files changed

+121
-74
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.techcourse.service;
2+
3+
import com.techcourse.dao.UserDao;
4+
import com.techcourse.dao.UserHistoryDao;
5+
import com.techcourse.domain.User;
6+
import com.techcourse.domain.UserHistory;
7+
8+
public class AppUserService implements UserService {
9+
10+
private final UserDao userDao;
11+
private final UserHistoryDao userHistoryDao;
12+
13+
public AppUserService(final UserDao userDao, final UserHistoryDao userHistoryDao) {
14+
this.userDao = userDao;
15+
this.userHistoryDao = userHistoryDao;
16+
}
17+
18+
@Override
19+
public User findById(final long id) {
20+
return userDao.findById(id);
21+
}
22+
23+
@Override
24+
public void insert(final User user) {
25+
userDao.insert(user);
26+
}
27+
28+
@Override
29+
public void changePassword(final long id, final String newPassword, final String createdBy) {
30+
final var user = findById(id);
31+
user.changePassword(newPassword);
32+
userDao.update(user);
33+
userHistoryDao.log(new UserHistory(user, createdBy));
34+
}
35+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.techcourse.service;
2+
3+
import com.techcourse.domain.User;
4+
import com.interface21.dao.DataAccessException;
5+
import com.interface21.jdbc.datasource.DataSourceUtils;
6+
import com.interface21.transaction.support.TransactionSynchronizationManager;
7+
8+
import javax.sql.DataSource;
9+
import java.sql.Connection;
10+
import java.sql.SQLException;
11+
12+
public class TxUserService implements UserService {
13+
14+
private final UserService userService;
15+
private final DataSource dataSource;
16+
17+
public TxUserService(final UserService userService, final DataSource dataSource) {
18+
this.userService = userService;
19+
this.dataSource = dataSource;
20+
}
21+
22+
@Override
23+
public User findById(final long id) {
24+
return userService.findById(id);
25+
}
26+
27+
@Override
28+
public void insert(final User user) {
29+
userService.insert(user);
30+
}
31+
32+
@Override
33+
public void changePassword(final long id, final String newPassword, final String createdBy) {
34+
final Connection connection = DataSourceUtils.getConnection(dataSource);
35+
TransactionSynchronizationManager.bindResource(dataSource, connection);
36+
37+
boolean originalAutoCommit = true;
38+
try {
39+
originalAutoCommit = connection.getAutoCommit();
40+
connection.setAutoCommit(false);
41+
42+
userService.changePassword(id, newPassword, createdBy);
43+
44+
connection.commit();
45+
} catch (Exception e) {
46+
try {
47+
connection.rollback();
48+
} catch (SQLException rollbackException) {
49+
throw new DataAccessException("Failed to rollback transaction", rollbackException);
50+
}
51+
throw new DataAccessException(e);
52+
} finally {
53+
try {
54+
connection.setAutoCommit(originalAutoCommit);
55+
} catch (SQLException e) {
56+
throw new DataAccessException("Failed to reset autoCommit", e);
57+
}
58+
try {
59+
TransactionSynchronizationManager.unbindResource(dataSource);
60+
} catch (IllegalStateException e) {
61+
throw new DataAccessException("Failed to unbind resource", e);
62+
}
63+
try {
64+
DataSourceUtils.releaseConnection(connection, dataSource);
65+
} catch (Exception e) {
66+
throw new DataAccessException("Failed to release connection", e);
67+
}
68+
}
69+
}
70+
71+
}
Lines changed: 4 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,12 @@
11
package com.techcourse.service;
22

3-
import com.techcourse.dao.UserDao;
4-
import com.techcourse.dao.UserHistoryDao;
53
import com.techcourse.domain.User;
6-
import com.techcourse.domain.UserHistory;
7-
import com.interface21.dao.DataAccessException;
8-
import com.interface21.jdbc.datasource.DataSourceUtils;
9-
import com.interface21.transaction.support.TransactionSynchronizationManager;
104

11-
import javax.sql.DataSource;
12-
import java.sql.Connection;
13-
import java.sql.SQLException;
5+
public interface UserService {
146

15-
public class UserService {
7+
User findById(final long id);
168

17-
private final UserDao userDao;
18-
private final UserHistoryDao userHistoryDao;
19-
private final DataSource dataSource;
9+
void insert(final User user);
2010

21-
public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao) {
22-
this.userDao = userDao;
23-
this.userHistoryDao = userHistoryDao;
24-
this.dataSource = null;
25-
}
26-
27-
public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao, final DataSource dataSource) {
28-
this.userDao = userDao;
29-
this.userHistoryDao = userHistoryDao;
30-
this.dataSource = dataSource;
31-
}
32-
33-
public User findById(final long id) {
34-
return userDao.findById(id);
35-
}
36-
37-
public void insert(final User user) {
38-
userDao.insert(user);
39-
}
40-
41-
public void changePassword(final long id, final String newPassword, final String createBy) {
42-
if (dataSource == null) {
43-
// 트랜잭션 없이 실행
44-
executeChangePassword(id, newPassword, createBy);
45-
return;
46-
}
47-
48-
// 트랜잭션과 함께 실행
49-
final Connection connection = DataSourceUtils.getConnection(dataSource);
50-
try {
51-
connection.setAutoCommit(false);
52-
53-
executeChangePassword(id, newPassword, createBy);
54-
55-
connection.commit();
56-
} catch (Exception e) {
57-
try {
58-
connection.rollback();
59-
} catch (SQLException rollbackException) {
60-
throw new DataAccessException("Failed to rollback transaction", rollbackException);
61-
}
62-
throw new DataAccessException(e);
63-
} finally {
64-
TransactionSynchronizationManager.unbindResource(dataSource);
65-
DataSourceUtils.releaseConnection(connection, dataSource);
66-
}
67-
}
68-
69-
private void executeChangePassword(final long id, final String newPassword, final String createBy) {
70-
final var user = findById(id);
71-
user.changePassword(newPassword);
72-
userDao.update(user);
73-
userHistoryDao.log(new UserHistory(user, createBy));
74-
}
11+
void changePassword(final long id, final String newPassword, final String createdBy);
7512
}

app/src/test/java/com/techcourse/service/UserServiceTest.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ void setUp() {
3131
@Test
3232
void testChangePassword() {
3333
final var userHistoryDao = new UserHistoryDao(jdbcTemplate);
34-
final var userService = new UserService(userDao, userHistoryDao, DataSourceConfig.getInstance());
34+
// 애플리케이션 서비스
35+
final var appUserService = new AppUserService(userDao, userHistoryDao);
36+
// 트랜잭션 서비스 추상화
37+
final var userService = new TxUserService(appUserService, DataSourceConfig.getInstance());
3538

3639
final var newPassword = "qqqqq";
3740
final var createBy = "gugu";
@@ -46,13 +49,16 @@ void testChangePassword() {
4649
void testTransactionRollback() {
4750
// 트랜잭션 롤백 테스트를 위해 mock으로 교체
4851
final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate);
49-
final var userService = new UserService(userDao, userHistoryDao, DataSourceConfig.getInstance());
52+
// 애플리케이션 서비스
53+
final var appUserService = new AppUserService(userDao, userHistoryDao);
54+
// 트랜잭션 서비스 추상화
55+
final var userService = new TxUserService(appUserService, DataSourceConfig.getInstance());
5056

5157
final var newPassword = "newPassword";
52-
final var createBy = "gugu";
58+
final var createdBy = "gugu";
5359
// 트랜잭션이 정상 동작하는지 확인하기 위해 의도적으로 MockUserHistoryDao에서 예외를 발생시킨다.
5460
assertThrows(DataAccessException.class,
55-
() -> userService.changePassword(1L, newPassword, createBy));
61+
() -> userService.changePassword(1L, newPassword, createdBy));
5662

5763
final var actual = userService.findById(1L);
5864

jdbc/src/main/java/com/interface21/jdbc/datasource/DataSourceUtils.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd
1919
}
2020

2121
try {
22-
connection = dataSource.getConnection();
23-
TransactionSynchronizationManager.bindResource(dataSource, connection);
24-
return connection;
22+
return dataSource.getConnection();
2523
} catch (SQLException ex) {
2624
throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex);
2725
}

0 commit comments

Comments
 (0)