From 932af39d8501fe801688c0af5fbbc19e4e3aa3dd Mon Sep 17 00:00:00 2001 From: nuyh Date: Mon, 9 Oct 2023 14:50:36 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20TransactionSynchronizationManager?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransactionSynchronizationManager.java | 39 ++++++++- ...TransactionSynchronizationManagerTest.java | 80 +++++++++++++++++++ 2 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 jdbc/src/test/java/org/springframework/transaction/support/TransactionSynchronizationManagerTest.java diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java index 715557fc66..ac0c4538dc 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -1,23 +1,56 @@ package org.springframework.transaction.support; +import javax.annotation.Nullable; import javax.sql.DataSource; import java.sql.Connection; +import java.util.HashMap; import java.util.Map; +import static java.util.Objects.isNull; + public abstract class TransactionSynchronizationManager { private static final ThreadLocal> resources = new ThreadLocal<>(); - private TransactionSynchronizationManager() {} + private TransactionSynchronizationManager() { + } + @Nullable public static Connection getResource(DataSource key) { - return null; + Map connections = getResources(); + return connections.get(key); + } + + private static Map getResources() { + if (isNull(resources.get())) { + resources.set(new HashMap<>()); + } + + return resources.get(); } public static void bindResource(DataSource key, Connection value) { + final Map resources = getResources(); + + if (resources.containsKey(key)) { + throw new IllegalStateException("이미 커넥션이 존재합니다."); + } + resources.put(key, value); } public static Connection unbindResource(DataSource key) { - return null; + final Map resources = getResources(); + final Connection connection = resources.get(key); + + if (isNull(connection)) { + throw new IllegalStateException("커넥션이 존재하지 않습니다."); + } + resources.remove(key); + + if (resources.isEmpty()) { + TransactionSynchronizationManager.resources.remove(); + } + + return connection; } } diff --git a/jdbc/src/test/java/org/springframework/transaction/support/TransactionSynchronizationManagerTest.java b/jdbc/src/test/java/org/springframework/transaction/support/TransactionSynchronizationManagerTest.java new file mode 100644 index 0000000000..9f784deebc --- /dev/null +++ b/jdbc/src/test/java/org/springframework/transaction/support/TransactionSynchronizationManagerTest.java @@ -0,0 +1,80 @@ +package org.springframework.transaction.support; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import javax.sql.DataSource; +import java.sql.Connection; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.BDDMockito.mock; + +class TransactionSynchronizationManagerTest { + + @Test + @DisplayName("커넥션을 저장할 수 있다") + void bindResource() { + //given + final DataSource dataSource = mock(DataSource.class); + final Connection connection = mock(Connection.class); + + //when, then + assertDoesNotThrow(() -> TransactionSynchronizationManager.bindResource(dataSource, connection)); + } + + @Test + @DisplayName("이미 존재하는 커넥션이 있을 때 저장하면 예외가 발생한다") + void bindResource_fail() { + //given + final DataSource dataSource = mock(DataSource.class); + final Connection connection = mock(Connection.class); + + TransactionSynchronizationManager.bindResource(dataSource, connection); + + //when, then + assertThatThrownBy(() -> TransactionSynchronizationManager.bindResource(dataSource, connection)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("이미 커넥션이 존재합니다."); + } + + @Test + @DisplayName("커넥션을 가져올 수 있다") + void getResource() { + //given + final DataSource dataSource = mock(DataSource.class); + final Connection connection = mock(Connection.class); + TransactionSynchronizationManager.bindResource(dataSource, connection); + + //when + final Connection resource = TransactionSynchronizationManager.getResource(dataSource); + + //then + assertThat(resource).isEqualTo(connection); + } + + @Test + @DisplayName("커넥션을 제거할 수 있다") + void unbindResource() { + //given + final DataSource dataSource = mock(DataSource.class); + final Connection connection = mock(Connection.class); + TransactionSynchronizationManager.bindResource(dataSource, connection); + + //when, then + assertDoesNotThrow(() -> TransactionSynchronizationManager.unbindResource(dataSource)); + } + + @Test + @DisplayName("커넥션을 제거할 때 이미 존재하지 않으면 예외가 발생한다") + void unbindResource_fail() { + //given + final DataSource dataSource = mock(DataSource.class); + + //when, then + assertThatThrownBy(() -> TransactionSynchronizationManager.unbindResource(dataSource)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("커넥션이 존재하지 않습니다."); + } +} From 597e1304527b1f9828a784088603ed036e2f1df3 Mon Sep 17 00:00:00 2001 From: nuyh Date: Mon, 9 Oct 2023 14:55:53 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20=EC=BB=A4=EB=84=A5=EC=85=98=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20DataSourceUtils=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/service/UserService.java | 21 +++++++--- .../jdbc/datasource/ConnectionManager.java | 40 ------------------- 2 files changed, 15 insertions(+), 46 deletions(-) delete mode 100644 jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionManager.java diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 0391746748..86a71fd7e7 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -6,9 +6,11 @@ import com.techcourse.domain.User; import com.techcourse.domain.UserHistory; import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.datasource.ConnectionManager; +import org.springframework.jdbc.datasource.DataSourceUtils; +import javax.sql.DataSource; import java.sql.Connection; +import java.sql.SQLException; public class UserService { @@ -29,9 +31,8 @@ public void insert(final User user) { } public void changePassword(final long id, final String newPassword, final String createBy) { - final ConnectionManager connectionManager = new ConnectionManager(DataSourceConfig.getInstance()); - - final Connection connection = connectionManager.getConnection(); + final DataSource dataSource = DataSourceConfig.getInstance(); + final Connection connection = DataSourceUtils.getConnection(dataSource); try { connection.setAutoCommit(false); @@ -43,10 +44,18 @@ public void changePassword(final long id, final String newPassword, final String connection.commit(); } catch (final Exception e) { - connectionManager.rollback(connection); + rollback(connection); throw new DataAccessException(e); } finally { - connectionManager.close(connection); + DataSourceUtils.releaseConnection(connection, dataSource); + } + } + + public void rollback(final Connection connection) { + try { + connection.rollback(); + } catch (final SQLException e) { + throw new DataAccessException(e); } } } diff --git a/jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionManager.java b/jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionManager.java deleted file mode 100644 index 1fa0160367..0000000000 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/ConnectionManager.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.springframework.jdbc.datasource; - -import org.springframework.dao.DataAccessException; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.SQLException; - -public class ConnectionManager { - - private final DataSource dataSource; - - public ConnectionManager(final DataSource dataSource) { - this.dataSource = dataSource; - } - - public Connection getConnection() { - try { - return dataSource.getConnection(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } - - public void close(final Connection connection) { - try { - connection.close(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } - - public void rollback(final Connection connection) { - try { - connection.rollback(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } -} From 2d3b0c2d97b56c9168220d2efff1347e3d6698c1 Mon Sep 17 00:00:00 2001 From: nuyh Date: Mon, 9 Oct 2023 16:47:47 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=20DAO=EA=B0=80=20=ED=98=84?= =?UTF-8?q?=EC=9E=AC=20=EC=8A=A4=EB=A0=88=EB=93=9C=EC=9D=98=20=EC=BB=A4?= =?UTF-8?q?=EB=84=A5=EC=85=98=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/dao/UserDao.java | 11 +++++++++-- .../main/java/com/techcourse/dao/UserHistoryDao.java | 11 +++++++++-- app/src/test/java/com/techcourse/dao/UserDaoTest.java | 4 +--- .../com/techcourse/service/MockUserHistoryDao.java | 4 +--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index b7b07c5f79..c05e188563 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,8 +1,10 @@ package com.techcourse.dao; +import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.User; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; import java.sql.Connection; @@ -32,11 +34,16 @@ public void insert(final User user) { jdbcTemplate.executeUpdate(sql, user.getAccount(), user.getPassword(), user.getEmail()); } - public void update(final Connection connection, final User user) { + public void update(final User user) { final String sql = "UPDATE users SET account = ?, password = ?, email = ? WHERE id = ?"; final long userId = user.getId(); - jdbcTemplate.executeUpdate(connection, sql, user.getAccount(), user.getPassword(), user.getEmail(), userId); + jdbcTemplate.executeUpdate(getConnection(), sql, user.getAccount(), user.getPassword(), user.getEmail(), userId); + } + + private Connection getConnection() { + final DataSource dataSource = DataSourceConfig.getInstance(); + return DataSourceUtils.getConnection(dataSource); } public List findAll() { diff --git a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java index b9eaa04a94..d12855f720 100644 --- a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java +++ b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java @@ -1,7 +1,9 @@ package com.techcourse.dao; +import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.UserHistory; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; import java.sql.Connection; @@ -18,11 +20,11 @@ public UserHistoryDao(final JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } - public void log(final Connection connection, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { final String sql = "insert into user_history (user_id, account, password, email, created_at, created_by) " + "values (?, ?, ?, ?, ?, ?)"; - jdbcTemplate.executeUpdate(connection, + jdbcTemplate.executeUpdate(getConnection(), sql, userHistory.getUserId(), userHistory.getAccount(), @@ -32,4 +34,9 @@ public void log(final Connection connection, final UserHistory userHistory) { userHistory.getCreateBy() ); } + + private Connection getConnection() { + final DataSource dataSource = DataSourceConfig.getInstance(); + return DataSourceUtils.getConnection(dataSource); + } } diff --git a/app/src/test/java/com/techcourse/dao/UserDaoTest.java b/app/src/test/java/com/techcourse/dao/UserDaoTest.java index bbd19258dd..1b0440ed41 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.sql.Connection; import java.sql.SQLException; import static org.assertj.core.api.Assertions.assertThat; @@ -62,8 +61,7 @@ void update() throws SQLException { final var user = userDao.findById(1L); user.changePassword(newPassword); - final Connection connection = DataSourceConfig.getInstance().getConnection(); - userDao.update(connection, user); + userDao.update(user); final var actual = userDao.findById(1L); diff --git a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java index 9937b42bbc..2ee12b195f 100644 --- a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java +++ b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java @@ -5,8 +5,6 @@ import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; -import java.sql.Connection; - public class MockUserHistoryDao extends UserHistoryDao { public MockUserHistoryDao(final JdbcTemplate jdbcTemplate) { @@ -14,7 +12,7 @@ public MockUserHistoryDao(final JdbcTemplate jdbcTemplate) { } @Override - public void log(final Connection connection, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { throw new DataAccessException(); } } From 422eaac9cecd5f8c69756efb49c667479bd05f11 Mon Sep 17 00:00:00 2001 From: nuyh Date: Mon, 9 Oct 2023 16:48:23 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20Application=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EB=A7=8C=20=EC=9E=88=EB=8A=94=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=99=80=20=ED=8A=B8=EB=9E=9C=EC=9E=AD=EC=85=98=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/service/AppUserService.java | 36 ++++++++++++ .../com/techcourse/service/TxUserService.java | 56 +++++++++++++++++++ .../com/techcourse/service/UserService.java | 56 ++----------------- .../techcourse/service/UserServiceTest.java | 7 ++- .../jdbc/datasource/DataSourceUtils.java | 5 +- .../TransactionSynchronizationManager.java | 27 +++++---- 6 files changed, 120 insertions(+), 67 deletions(-) create mode 100644 app/src/main/java/com/techcourse/service/AppUserService.java create mode 100644 app/src/main/java/com/techcourse/service/TxUserService.java diff --git a/app/src/main/java/com/techcourse/service/AppUserService.java b/app/src/main/java/com/techcourse/service/AppUserService.java new file mode 100644 index 0000000000..9b27bb0e32 --- /dev/null +++ b/app/src/main/java/com/techcourse/service/AppUserService.java @@ -0,0 +1,36 @@ +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(final long id) { + return userDao.findById(id); + } + + @Override + public void insert(final User user) { + userDao.insert(user); + } + + @Override + public void changePassword(final long id, final String newPassword, final String createBy) { + final var user = findById(id); + user.changePassword(newPassword); + + userDao.update(user); + userHistoryDao.log(new UserHistory(user, createBy)); + } +} diff --git a/app/src/main/java/com/techcourse/service/TxUserService.java b/app/src/main/java/com/techcourse/service/TxUserService.java new file mode 100644 index 0000000000..70207dffea --- /dev/null +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -0,0 +1,56 @@ +package com.techcourse.service; + +import com.techcourse.config.DataSourceConfig; +import com.techcourse.domain.User; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.DataSourceUtils; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; + +public class TxUserService implements UserService { + + private final UserService userService; + + public TxUserService(final UserService userService) { + this.userService = userService; + } + + @Override + public User findById(final long id) { + return userService.findById(id); + } + + @Override + public void insert(final User user) { + userService.insert(user); + } + + @Override + public void changePassword(final long id, final String newPassword, final String createBy) { + final DataSource dataSource = DataSourceConfig.getInstance(); + final Connection connection = DataSourceUtils.getConnection(dataSource); + + try { + connection.setAutoCommit(false); + + userService.changePassword(id, newPassword, createBy); + + connection.commit(); + } catch (final Exception e) { + rollback(connection); + throw new DataAccessException(e); + } finally { + DataSourceUtils.releaseConnection(connection, dataSource); + } + } + + public void rollback(final Connection connection) { + try { + connection.rollback(); + } catch (final SQLException e) { + throw new DataAccessException(e); + } + } +} diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 86a71fd7e7..f9c5b63f4a 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -1,61 +1,13 @@ 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.dao.DataAccessException; -import org.springframework.jdbc.datasource.DataSourceUtils; -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; - } + void changePassword(final long id, final String newPassword, final String createBy); - 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) { - final DataSource dataSource = DataSourceConfig.getInstance(); - final Connection connection = DataSourceUtils.getConnection(dataSource); - 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 (final Exception e) { - rollback(connection); - throw new DataAccessException(e); - } finally { - DataSourceUtils.releaseConnection(connection, dataSource); - } - } - - public void rollback(final Connection connection) { - try { - connection.rollback(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } } diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index 3925a8b534..fdda8f2ddd 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -31,7 +31,7 @@ void setUp() { @Test void testChangePassword() { final var userHistoryDao = new UserHistoryDao(jdbcTemplate); - final var userService = new UserService(userDao, userHistoryDao); + final var userService = new AppUserService(userDao, userHistoryDao); final var newPassword = "qqqqq"; final var createBy = "gugu"; @@ -46,7 +46,10 @@ void testChangePassword() { void testTransactionRollback() { // 트랜잭션 롤백 테스트를 위해 mock으로 교체 final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate); - final var userService = new UserService(userDao, userHistoryDao); + // 애플리케이션 서비스 + final var appUserService = new AppUserService(userDao, userHistoryDao); + // 트랜잭션 서비스 추상화 + final var userService = new TxUserService(appUserService); final var newPassword = "newPassword"; final var createBy = "gugu"; diff --git a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java index 3c40bfec52..bf5692ecd0 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -10,7 +10,8 @@ // 4단계 미션에서 사용할 것 public abstract class DataSourceUtils { - private DataSourceUtils() {} + private DataSourceUtils() { + } public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { Connection connection = TransactionSynchronizationManager.getResource(dataSource); @@ -32,6 +33,8 @@ public static void releaseConnection(Connection connection, DataSource dataSourc connection.close(); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection"); + } finally { + TransactionSynchronizationManager.unbindResource(dataSource); } } } diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java index ac0c4538dc..8c4a0058c1 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -17,37 +17,40 @@ private TransactionSynchronizationManager() { @Nullable public static Connection getResource(DataSource key) { - Map connections = getResources(); + final Map connections = getConnections(); return connections.get(key); } - private static Map getResources() { - if (isNull(resources.get())) { - resources.set(new HashMap<>()); + private static Map getConnections() { + Map connections = resources.get(); + + if (isNull(connections)) { + connections = new HashMap<>(); + resources.set(connections); } - return resources.get(); + return connections; } public static void bindResource(DataSource key, Connection value) { - final Map resources = getResources(); + final Map connections = getConnections(); - if (resources.containsKey(key)) { + if (connections.containsKey(key)) { throw new IllegalStateException("이미 커넥션이 존재합니다."); } - resources.put(key, value); + connections.put(key, value); } public static Connection unbindResource(DataSource key) { - final Map resources = getResources(); - final Connection connection = resources.get(key); + final Map connections = getConnections(); + final Connection connection = connections.get(key); if (isNull(connection)) { throw new IllegalStateException("커넥션이 존재하지 않습니다."); } - resources.remove(key); + connections.remove(key); - if (resources.isEmpty()) { + if (connections.isEmpty()) { TransactionSynchronizationManager.resources.remove(); } From 995081d068ddc1e66cf49c33d36a475b07e3d7a2 Mon Sep 17 00:00:00 2001 From: nuyh Date: Mon, 9 Oct 2023 17:02:05 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20rollback=EC=9D=98=20=EC=97=AD?= =?UTF-8?q?=ED=95=A0=20TransactionSynchronizationManager=EC=97=90=EA=B2=8C?= =?UTF-8?q?=20=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/service/TxUserService.java | 12 ++---------- .../TransactionSynchronizationManager.java | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/TxUserService.java b/app/src/main/java/com/techcourse/service/TxUserService.java index 70207dffea..14b9b51647 100644 --- a/app/src/main/java/com/techcourse/service/TxUserService.java +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -4,10 +4,10 @@ import com.techcourse.domain.User; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.transaction.support.TransactionSynchronizationManager; import javax.sql.DataSource; import java.sql.Connection; -import java.sql.SQLException; public class TxUserService implements UserService { @@ -39,18 +39,10 @@ public void changePassword(final long id, final String newPassword, final String connection.commit(); } catch (final Exception e) { - rollback(connection); + TransactionSynchronizationManager.rollback(connection); throw new DataAccessException(e); } finally { DataSourceUtils.releaseConnection(connection, dataSource); } } - - public void rollback(final Connection connection) { - try { - connection.rollback(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } } diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java index 8c4a0058c1..038dc62ad7 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -1,8 +1,11 @@ package org.springframework.transaction.support; +import org.springframework.dao.DataAccessException; + import javax.annotation.Nullable; import javax.sql.DataSource; import java.sql.Connection; +import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -16,7 +19,7 @@ private TransactionSynchronizationManager() { } @Nullable - public static Connection getResource(DataSource key) { + public static Connection getResource(final DataSource key) { final Map connections = getConnections(); return connections.get(key); } @@ -32,7 +35,7 @@ private static Map getConnections() { return connections; } - public static void bindResource(DataSource key, Connection value) { + public static void bindResource(final DataSource key, final Connection value) { final Map connections = getConnections(); if (connections.containsKey(key)) { @@ -41,7 +44,7 @@ public static void bindResource(DataSource key, Connection value) { connections.put(key, value); } - public static Connection unbindResource(DataSource key) { + public static Connection unbindResource(final DataSource key) { final Map connections = getConnections(); final Connection connection = connections.get(key); @@ -56,4 +59,12 @@ public static Connection unbindResource(DataSource key) { return connection; } + + public static void rollback(final Connection connection) { + try { + connection.rollback(); + } catch (final SQLException e) { + throw new DataAccessException(e); + } + } } From ee33f0e6e41acce8555c7585fdaffcc18790add6 Mon Sep 17 00:00:00 2001 From: nuyh Date: Tue, 10 Oct 2023 22:49:51 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20close(),=20unbindResource()=20?= =?UTF-8?q?=EA=B0=99=EC=9D=B4=20=EC=8B=A4=ED=96=89=20=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/springframework/jdbc/datasource/DataSourceUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java index bf5692ecd0..1d8f96dc9c 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -31,10 +31,9 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd public static void releaseConnection(Connection connection, DataSource dataSource) { try { connection.close(); + TransactionSynchronizationManager.unbindResource(dataSource); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection"); - } finally { - TransactionSynchronizationManager.unbindResource(dataSource); } } } From ab5398fc3659aba827f759cceb7dfbbf426eb4f6 Mon Sep 17 00:00:00 2001 From: nuyh Date: Tue, 10 Oct 2023 23:43:41 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20rollback=EC=9D=98=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20TxUserService=EC=97=90=EA=B2=8C=20=EC=9C=84?= =?UTF-8?q?=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/service/TxUserService.java | 16 +++++++++++----- .../TransactionSynchronizationManager.java | 11 ----------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/TxUserService.java b/app/src/main/java/com/techcourse/service/TxUserService.java index 14b9b51647..387ad0ded4 100644 --- a/app/src/main/java/com/techcourse/service/TxUserService.java +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -4,10 +4,10 @@ import com.techcourse.domain.User; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.transaction.support.TransactionSynchronizationManager; import javax.sql.DataSource; import java.sql.Connection; +import java.sql.SQLException; public class TxUserService implements UserService { @@ -34,15 +34,21 @@ public void changePassword(final long id, final String newPassword, final String try { connection.setAutoCommit(false); - userService.changePassword(id, newPassword, createBy); - connection.commit(); } catch (final Exception e) { - TransactionSynchronizationManager.rollback(connection); - throw new DataAccessException(e); + rollbackAndThrow(connection, e); } finally { DataSourceUtils.releaseConnection(connection, dataSource); } } + + private void rollbackAndThrow(final Connection connection, final Exception businessException) { + try { + connection.rollback(); + throw new DataAccessException(businessException); + } catch (final SQLException rollbackException) { + throw new DataAccessException(rollbackException); + } + } } diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java index 038dc62ad7..1f1fda39bf 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -1,11 +1,8 @@ package org.springframework.transaction.support; -import org.springframework.dao.DataAccessException; - import javax.annotation.Nullable; import javax.sql.DataSource; import java.sql.Connection; -import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -59,12 +56,4 @@ public static Connection unbindResource(final DataSource key) { return connection; } - - public static void rollback(final Connection connection) { - try { - connection.rollback(); - } catch (final SQLException e) { - throw new DataAccessException(e); - } - } }