From 781cc9bb14be11ab654d7c8a95826821b0ee478b Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Sat, 7 Oct 2023 15:15:16 +0900 Subject: [PATCH 01/12] =?UTF-8?q?refactor:=20Connection=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=A1=9C=20=EB=B0=9B=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 11 ----------- .../java/com/techcourse/dao/UserHistoryDao.java | 5 ++--- .../techcourse/service/MockUserHistoryDao.java | 3 +-- .../springframework/jdbc/core/JdbcTemplate.java | 5 ----- .../jdbc/core/PreparedStatementExecutor.java | 16 ++-------------- 5 files changed, 5 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 170dc965af..5bcbc81881 100644 --- a/app/src/main/java/com/techcourse/dao/UserDao.java +++ b/app/src/main/java/com/techcourse/dao/UserDao.java @@ -1,7 +1,6 @@ package com.techcourse.dao; import com.techcourse.domain.User; -import java.sql.Connection; import java.util.List; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -40,16 +39,6 @@ public void update(final User user) { jdbcTemplate.update(sql, account, password, email, id); } - public void update(final Connection connection, final User user) { - final var sql = "update users set account = ?, password = ?, email = ? where id = ?"; - final String account = user.getAccount(); - final String password = user.getPassword(); - final String email = user.getEmail(); - final long id = user.getId(); - - jdbcTemplate.update(connection, sql, account, password, email, id); - } - public List findAll() { final var sql = "select * from users"; diff --git a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java index 7eb35a1f6b..257373f9fc 100644 --- a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java +++ b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java @@ -1,7 +1,6 @@ package com.techcourse.dao; import com.techcourse.domain.UserHistory; -import java.sql.Connection; import org.springframework.jdbc.core.JdbcTemplate; public class UserHistoryDao { @@ -12,10 +11,10 @@ public UserHistoryDao(final JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } - public void log(final Connection connection, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { final var sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)"; - jdbcTemplate.update(connection, sql, + jdbcTemplate.update(sql, userHistory.getUserId(), userHistory.getAccount(), userHistory.getPassword(), userHistory.getEmail(), userHistory.getCreatedAt(), userHistory.getCreateBy() diff --git a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java index 4f6f9aba26..2ee12b195f 100644 --- a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java +++ b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java @@ -2,7 +2,6 @@ import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.UserHistory; -import java.sql.Connection; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -13,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(); } } diff --git a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java index 157257f0e7..ffa6d6fb55 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -1,6 +1,5 @@ package org.springframework.jdbc.core; -import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; @@ -21,10 +20,6 @@ public void update(final String sql, final Object... args) { preparedStatementExecutor.execute(sql, PreparedStatement::executeUpdate, args); } - public void update(final Connection connection, final String sql, final Object... args) { - preparedStatementExecutor.execute(connection, sql, PreparedStatement::executeUpdate, args); - } - public List query(final String sql, final RowMapper rowMapper, final Object... args) { return preparedStatementExecutor.execute(sql, pstmt -> { ResultSet resultSet = pstmt.executeQuery(); diff --git a/jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementExecutor.java b/jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementExecutor.java index ba4d584087..180b74bcaf 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementExecutor.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementExecutor.java @@ -19,21 +19,9 @@ public PreparedStatementExecutor(final DataSource dataSource) { this.dataSource = dataSource; } - public T execute(final Connection connection, final String sql, final PreparedStatementCallback preparedStatementCallback, final Object... args) { - try (final PreparedStatement pstmt = connection.prepareStatement(sql)) { - log.debug("query : {}", sql); - - setPreparedStatementArguments(pstmt, args); - return preparedStatementCallback.doInPreparedStatement(pstmt); - } catch (SQLException e) { - log.error(e.getMessage(), e); - throw new DataAccessException(e); - } - } - public T execute(final String sql, final PreparedStatementCallback preparedStatementCallback, final Object... args) { - try (final Connection connection = DataSourceUtils.getConnection(dataSource); - final PreparedStatement pstmt = connection.prepareStatement(sql)) { + Connection connection = DataSourceUtils.getConnection(dataSource); + try (final PreparedStatement pstmt = connection.prepareStatement(sql)) { log.debug("query : {}", sql); setPreparedStatementArguments(pstmt, args); From be7d4c9dfcc059b75e32aa1a24010428dd80d7b7 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Sat, 7 Oct 2023 15:18:52 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20TransactionSynchronizationManager?= =?UTF-8?q?=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EA=B5=AC=ED=98=84=ED=95=98?= =?UTF-8?q?=EC=97=AC=20UserService=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/service/UserService.java | 10 +++++----- .../TransactionSynchronizationManager.java | 20 ++++++++++++++++--- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 6e14b5a9b4..ec42129fd3 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -10,6 +10,7 @@ import javax.sql.DataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.transaction.support.TransactionSynchronizationManager; public class UserService { @@ -31,16 +32,14 @@ public void insert(final User user) { public void changePassword(final long id, final String newPassword, final String createBy) { DataSource dataSource = DataSourceConfig.getInstance(); - Connection connection = null; + Connection connection = DataSourceUtils.getConnection(dataSource); try { - connection = dataSource.getConnection(); connection.setAutoCommit(false); - final var user = findById(id); user.changePassword(newPassword); - userDao.update(connection, user); - userHistoryDao.log(connection, new UserHistory(user, createBy)); + userDao.update(user); + userHistoryDao.log(new UserHistory(user, createBy)); connection.commit(); } catch (SQLException e) { @@ -51,6 +50,7 @@ public void changePassword(final long id, final String newPassword, final String } } finally { DataSourceUtils.releaseConnection(connection, dataSource); + 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 715557fc66..d048813f2d 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,9 @@ package org.springframework.transaction.support; -import javax.sql.DataSource; import java.sql.Connection; +import java.util.HashMap; import java.util.Map; +import javax.sql.DataSource; public abstract class TransactionSynchronizationManager { @@ -11,13 +12,26 @@ public abstract class TransactionSynchronizationManager { private TransactionSynchronizationManager() {} public static Connection getResource(DataSource key) { - return null; + if (resources.get() == null) { + return null; + } + Map connectionMap = resources.get(); + return connectionMap.get(key); } public static void bindResource(DataSource key, Connection value) { + Map connectionMap = new HashMap<>(); + Connection mappedConnection = connectionMap.put(key, value); + if (mappedConnection != null) { + throw new IllegalStateException("fail to bind resource because of already exist bound thread"); + } + resources.set(connectionMap); } public static Connection unbindResource(DataSource key) { - return null; + Map connectionMap = resources.get(); + Connection connectionToRemove = connectionMap.get(key); + resources.remove(); + return connectionToRemove; } } From c2492f3055d7efa01ce526b57a16cc2db7033e17 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Sat, 7 Oct 2023 17:23:28 +0900 Subject: [PATCH 03/12] =?UTF-8?q?test:=20findById=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/service/UserServiceTest.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index 181407480a..3e7d22cf5a 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -25,14 +25,31 @@ void setUp() { this.userDao = new UserDao(jdbcTemplate); DatabasePopulatorUtils.execute(DataSourceConfig.getInstance(), ResourceNames.SCHEMA_RESOURCE_NAME); + DatabasePopulatorUtils.execute(DataSourceConfig.getInstance(), ResourceNames.TRUNCATE_RESOURCE_NAME); + } + + @Test + void testFindById() { final var user = new User("gugu", "password", "hkkang@woowahan.com"); userDao.insert(user); + + final var userHistoryDao = new UserHistoryDao(jdbcTemplate); + final var userService = new AppUserService(userDao, userHistoryDao); + + final var actual = userService.findById(1L); + + assertThat(actual).usingRecursiveComparison() + .ignoringFields("id") + .isEqualTo(user); } @Test void testChangePassword() { + final var user = new User("gugu", "password", "hkkang@woowahan.com"); + userDao.insert(user); + 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"; @@ -45,9 +62,15 @@ void testChangePassword() { @Test void testTransactionRollback() { + final var user = new User("gugu", "password", "hkkang@woowahan.com"); + userDao.insert(user); + // 트랜잭션 롤백 테스트를 위해 mock으로 교체 final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate); - final var userService = new UserService(userDao, userHistoryDao); + // Application Service + final var appUserService = new AppUserService(userDao, userHistoryDao); + // 트랜잭션 Service 추상화 + final var userService = new TxUserService(appUserService); final var newPassword = "newPassword"; final var createBy = "gugu"; From 74682d51e2c0107e419df59518d5219ce5c50025 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Sat, 7 Oct 2023 17:24:38 +0900 Subject: [PATCH 04/12] =?UTF-8?q?test:=20insert=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/techcourse/service/UserServiceTest.java | 13 +++++++++++++ app/src/test/resources/truncate.sql | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index 3e7d22cf5a..5cf8a5b813 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -28,6 +28,19 @@ void setUp() { DatabasePopulatorUtils.execute(DataSourceConfig.getInstance(), ResourceNames.TRUNCATE_RESOURCE_NAME); } + @Test + void testInsert() { + final var user = new User("gugu", "password", "hkkang@woowahan.com"); + userDao.insert(user); + + final var userHistoryDao = new UserHistoryDao(jdbcTemplate); + final var userService = new AppUserService(userDao, userHistoryDao); + + final var actual = userService.findById(1L); + + assertThat(actual).isNotNull(); + } + @Test void testFindById() { final var user = new User("gugu", "password", "hkkang@woowahan.com"); diff --git a/app/src/test/resources/truncate.sql b/app/src/test/resources/truncate.sql index e9368db0dc..555a6e1d96 100644 --- a/app/src/test/resources/truncate.sql +++ b/app/src/test/resources/truncate.sql @@ -1 +1 @@ -TRUNCATE TABLE USERS; +TRUNCATE TABLE USERS restart identity; From e5c6b0de1e1239033fd1ff54ab846ed16eee9b30 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Sat, 7 Oct 2023 17:26:49 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20=ED=8A=B8=EB=9E=9C=EC=9E=AD?= =?UTF-8?q?=EC=85=98=20=EB=8F=99=EA=B8=B0=ED=99=94=20&=20=ED=8A=B8?= =?UTF-8?q?=EB=9E=9C=EC=9E=AD=EC=85=98=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=ED=99=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/service/AppUserService.java | 35 +++++++++++ .../com/techcourse/service/TxUserService.java | 31 ++++++++++ .../com/techcourse/service/UserService.java | 54 ++-------------- .../transaction/ServiceCallback.java | 7 +++ .../transaction/ServiceExecutor.java | 7 +++ .../transaction/TransactionExecutor.java | 62 +++++++++++++++++++ 6 files changed, 146 insertions(+), 50 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 create mode 100644 jdbc/src/main/java/org/springframework/transaction/ServiceCallback.java create mode 100644 jdbc/src/main/java/org/springframework/transaction/ServiceExecutor.java create mode 100644 jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.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..a8d453b094 --- /dev/null +++ b/app/src/main/java/com/techcourse/service/AppUserService.java @@ -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(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..f96fbf8e4d --- /dev/null +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -0,0 +1,31 @@ +package com.techcourse.service; + +import com.techcourse.config.DataSourceConfig; +import com.techcourse.domain.User; +import org.springframework.transaction.TransactionExecutor; + +public class TxUserService implements UserService { + + private final UserService userService; + private final TransactionExecutor transactionExecutor; + + public TxUserService(final UserService userService) { + this.userService = userService; + this.transactionExecutor = new TransactionExecutor(DataSourceConfig.getInstance()); + } + + @Override + public User findById(final long id) { + return transactionExecutor.execute(() -> userService.findById(id), true); + } + + @Override + public void insert(final User user) { + transactionExecutor.execute(() -> userService.insert(user), false); + } + + @Override + public void changePassword(final long id, final String newPassword, final String createBy) { + transactionExecutor.execute(() -> userService.changePassword(id, newPassword, createBy), true); + } +} diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index ec42129fd3..42d01bf760 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -1,56 +1,10 @@ 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 java.sql.Connection; -import java.sql.SQLException; -import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.transaction.support.TransactionSynchronizationManager; -public class UserService { +public interface UserService { - private final UserDao userDao; - private final UserHistoryDao userHistoryDao; - - 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) { - DataSource dataSource = DataSourceConfig.getInstance(); - Connection connection = DataSourceUtils.getConnection(dataSource); - - try { - connection.setAutoCommit(false); - final var user = findById(id); - user.changePassword(newPassword); - userDao.update(user); - userHistoryDao.log(new UserHistory(user, createBy)); - - connection.commit(); - } catch (SQLException e) { - try { - connection.rollback(); - } catch (SQLException ex) { - throw new DataAccessException(ex); - } - } finally { - DataSourceUtils.releaseConnection(connection, dataSource); - TransactionSynchronizationManager.unbindResource(dataSource); - } - } + User findById(final long id); + void insert(final User user); + void changePassword(final long id, final String newPassword, final String createBy); } diff --git a/jdbc/src/main/java/org/springframework/transaction/ServiceCallback.java b/jdbc/src/main/java/org/springframework/transaction/ServiceCallback.java new file mode 100644 index 0000000000..f3027694fd --- /dev/null +++ b/jdbc/src/main/java/org/springframework/transaction/ServiceCallback.java @@ -0,0 +1,7 @@ +package org.springframework.transaction; + +@FunctionalInterface +public interface ServiceCallback { + + T doInAction(); +} diff --git a/jdbc/src/main/java/org/springframework/transaction/ServiceExecutor.java b/jdbc/src/main/java/org/springframework/transaction/ServiceExecutor.java new file mode 100644 index 0000000000..0b21ea50f6 --- /dev/null +++ b/jdbc/src/main/java/org/springframework/transaction/ServiceExecutor.java @@ -0,0 +1,7 @@ +package org.springframework.transaction; + +@FunctionalInterface +public interface ServiceExecutor { + + void doInAction(); +} diff --git a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java new file mode 100644 index 0000000000..d97ac36f21 --- /dev/null +++ b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java @@ -0,0 +1,62 @@ +package org.springframework.transaction; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +public class TransactionExecutor { + + private final DataSource dataSource; + + public TransactionExecutor(final DataSource dataSource) { + this.dataSource = dataSource; + } + + public void execute(final ServiceExecutor serviceExecutor, final boolean isReadOnly) { + Connection connection = DataSourceUtils.getConnection(dataSource); + + try { + connection.setAutoCommit(false); + connection.setReadOnly(isReadOnly); + serviceExecutor.doInAction(); + + connection.commit(); + } catch (SQLException e) { + try { + connection.rollback(); + } catch (SQLException ex) { + throw new DataAccessException(ex); + } + } finally { + DataSourceUtils.releaseConnection(connection, dataSource); + TransactionSynchronizationManager.unbindResource(dataSource); + } + } + + public T execute(final ServiceCallback serviceExecutor, boolean isReadOnly) { + Connection connection = DataSourceUtils.getConnection(dataSource); + + try { + connection.setAutoCommit(false); + connection.setReadOnly(isReadOnly); + + T result = serviceExecutor.doInAction(); + + connection.commit(); + return result; + } catch (SQLException e) { + try { + connection.rollback(); + } catch (SQLException ex) { + throw new DataAccessException(ex); + } + } finally { + DataSourceUtils.releaseConnection(connection, dataSource); + TransactionSynchronizationManager.unbindResource(dataSource); + } + return null; + } +} From 797af5a7d51627274e5953e076a7fcf6510b12a8 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Mon, 9 Oct 2023 14:05:17 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:=20=EA=B0=80=EB=8F=85=EC=84=B1?= =?UTF-8?q?=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/TransactionSynchronizationManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 d048813f2d..12a78219a7 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -12,10 +12,10 @@ public abstract class TransactionSynchronizationManager { private TransactionSynchronizationManager() {} public static Connection getResource(DataSource key) { - if (resources.get() == null) { + Map connectionMap = resources.get(); + if (connectionMap == null) { return null; } - Map connectionMap = resources.get(); return connectionMap.get(key); } From 01be39f7cf81c21b6d6d17e0f73b80e5695b2b47 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Mon, 9 Oct 2023 14:48:01 +0900 Subject: [PATCH 07/12] =?UTF-8?q?refactor:=20bindResource,=20unbindResourc?= =?UTF-8?q?e=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TransactionSynchronizationManager.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) 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 12a78219a7..69b679f128 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -20,18 +20,30 @@ public static Connection getResource(DataSource key) { } public static void bindResource(DataSource key, Connection value) { - Map connectionMap = new HashMap<>(); + Map connectionMap = resources.get(); + if (connectionMap == null) { + connectionMap = new HashMap<>(); + resources.set(connectionMap); + } + Connection mappedConnection = connectionMap.put(key, value); if (mappedConnection != null) { throw new IllegalStateException("fail to bind resource because of already exist bound thread"); } - resources.set(connectionMap); } public static Connection unbindResource(DataSource key) { Map connectionMap = resources.get(); - Connection connectionToRemove = connectionMap.get(key); - resources.remove(); + if (connectionMap == null) { + return null; + } + Connection connectionToRemove = connectionMap.remove(key); + if (connectionToRemove == null) { + throw new IllegalStateException("fail to unbind resource because of not found value"); + } + if (connectionMap.isEmpty()) { + resources.remove(); + } return connectionToRemove; } } From 90875bfb676e5fc8a24d4620bfd395c4b454fa3d Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Mon, 9 Oct 2023 15:10:53 +0900 Subject: [PATCH 08/12] =?UTF-8?q?refactor:=20Resource=20unbind=EA=B0=80=20?= =?UTF-8?q?=EB=A8=BC=EC=A0=80=20=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/springframework/transaction/TransactionExecutor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java index d97ac36f21..141b14842e 100644 --- a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java @@ -31,8 +31,8 @@ public void execute(final ServiceExecutor serviceExecutor, final boolean isReadO throw new DataAccessException(ex); } } finally { - DataSourceUtils.releaseConnection(connection, dataSource); TransactionSynchronizationManager.unbindResource(dataSource); + DataSourceUtils.releaseConnection(connection, dataSource); } } @@ -54,8 +54,8 @@ public T execute(final ServiceCallback serviceExecutor, boolean isReadOnl throw new DataAccessException(ex); } } finally { - DataSourceUtils.releaseConnection(connection, dataSource); TransactionSynchronizationManager.unbindResource(dataSource); + DataSourceUtils.releaseConnection(connection, dataSource); } return null; } From a876ec6a613e03e16fbb8b21c46a5e8ef3ae990b Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Mon, 9 Oct 2023 15:16:12 +0900 Subject: [PATCH 09/12] =?UTF-8?q?refactor:=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/springframework/transaction/TransactionExecutor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java index 141b14842e..086eabcf24 100644 --- a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java @@ -36,14 +36,14 @@ public void execute(final ServiceExecutor serviceExecutor, final boolean isReadO } } - public T execute(final ServiceCallback serviceExecutor, boolean isReadOnly) { + public T execute(final ServiceCallback serviceCallback, boolean isReadOnly) { Connection connection = DataSourceUtils.getConnection(dataSource); try { connection.setAutoCommit(false); connection.setReadOnly(isReadOnly); - T result = serviceExecutor.doInAction(); + T result = serviceCallback.doInAction(); connection.commit(); return result; From ae6ee4372e4b932e1c0348120cf70e6ac639c650 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Mon, 9 Oct 2023 15:34:36 +0900 Subject: [PATCH 10/12] =?UTF-8?q?refactor:=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EA=B5=AC=EC=B2=B4?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/service/TxUserService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/TxUserService.java b/app/src/main/java/com/techcourse/service/TxUserService.java index f96fbf8e4d..d217fd3859 100644 --- a/app/src/main/java/com/techcourse/service/TxUserService.java +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -9,8 +9,8 @@ public class TxUserService implements UserService { private final UserService userService; private final TransactionExecutor transactionExecutor; - public TxUserService(final UserService userService) { - this.userService = userService; + public TxUserService(final AppUserService appUserService) { + this.userService = appUserService; this.transactionExecutor = new TransactionExecutor(DataSourceConfig.getInstance()); } From 9ea549724ee3f521e3210be55a378bc420c0f23e Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Tue, 10 Oct 2023 09:47:25 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:=20unbindResource=20=EC=B1=85?= =?UTF-8?q?=EC=9E=84=20DatasourceUtils=EB=A1=9C=20=EC=9C=84=EC=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springframework/jdbc/datasource/DataSourceUtils.java | 8 ++++---- .../springframework/transaction/TransactionExecutor.java | 3 --- 2 files changed, 4 insertions(+), 7 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 3c40bfec52..9626b50011 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -1,11 +1,10 @@ package org.springframework.jdbc.datasource; -import org.springframework.jdbc.CannotGetJdbcConnectionException; -import org.springframework.transaction.support.TransactionSynchronizationManager; - -import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; +import javax.sql.DataSource; +import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.transaction.support.TransactionSynchronizationManager; // 4단계 미션에서 사용할 것 public abstract class DataSourceUtils { @@ -29,6 +28,7 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd public static void releaseConnection(Connection connection, DataSource dataSource) { try { + TransactionSynchronizationManager.unbindResource(dataSource); connection.close(); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection"); diff --git a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java index 086eabcf24..676adc413d 100644 --- a/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/TransactionExecutor.java @@ -5,7 +5,6 @@ import javax.sql.DataSource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.transaction.support.TransactionSynchronizationManager; public class TransactionExecutor { @@ -31,7 +30,6 @@ public void execute(final ServiceExecutor serviceExecutor, final boolean isReadO throw new DataAccessException(ex); } } finally { - TransactionSynchronizationManager.unbindResource(dataSource); DataSourceUtils.releaseConnection(connection, dataSource); } } @@ -54,7 +52,6 @@ public T execute(final ServiceCallback serviceCallback, boolean isReadOnl throw new DataAccessException(ex); } } finally { - TransactionSynchronizationManager.unbindResource(dataSource); DataSourceUtils.releaseConnection(connection, dataSource); } return null; From 0cde77ed82241c147a7d4301d76e60c3a4f2a000 Mon Sep 17 00:00:00 2001 From: sh111-coder Date: Wed, 11 Oct 2023 09:31:32 +0900 Subject: [PATCH 12/12] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=AF=B8=20?= =?UTF-8?q?=EC=A1=B4=EC=9E=AC=ED=95=98=EB=8A=94=20Key=EC=9D=BC=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EB=A8=BC=EC=A0=80=20=EC=98=88=EC=99=B8=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/TransactionSynchronizationManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 69b679f128..7d7287f389 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -26,10 +26,11 @@ public static void bindResource(DataSource key, Connection value) { resources.set(connectionMap); } - Connection mappedConnection = connectionMap.put(key, value); - if (mappedConnection != null) { + if (connectionMap.containsKey(key)) { throw new IllegalStateException("fail to bind resource because of already exist bound thread"); } + + connectionMap.put(key, value); } public static Connection unbindResource(DataSource key) {