From 72db1786d3821280d57e08afac2f378ef8e24a0e Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 9 Oct 2023 05:29:32 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20Transaction=20synchronization?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/techcourse/dao/UserDao.java | 6 ------ .../com/techcourse/dao/UserHistoryDao.java | 5 ++--- .../com/techcourse/service/UserService.java | 18 +++++++--------- .../service/MockUserHistoryDao.java | 3 +-- .../jdbc/core/AutoClosableTemplate.java | 12 ++--------- .../jdbc/datasource/DataSourceUtils.java | 11 +++++----- .../TransactionSynchronizationManager.java | 21 ++++++++++++++++--- 7 files changed, 36 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDao.java b/app/src/main/java/com/techcourse/dao/UserDao.java index 73ead66878..2941d0b407 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 javax.sql.DataSource; import org.slf4j.Logger; @@ -42,11 +41,6 @@ public void update(final User user) { jdbcTemplate.execute(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); } - public void update(final Connection conn, final User user) { - final var sql = "update users set account = ?, password = ?, email = ? where id = ?"; - jdbcTemplate.execute(conn, sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); - } - public List findAll() { final var sql = "select id, account, password, email from users"; return jdbcTemplate.query(sql, USER_ROW_MAPPER); diff --git a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java index 483e5c650e..5332550f15 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 javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,7 +20,7 @@ public UserHistoryDao(final JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } - public void log(final Connection conn, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { final var sql = "insert into user_history (" + "user_id, " + "account, " @@ -33,7 +32,7 @@ public void log(final Connection conn, final UserHistory userHistory) { log.debug("query = {}", sql); - jdbcTemplate.execute(conn, sql, + jdbcTemplate.execute(sql, userHistory.getUserId(), userHistory.getAccount(), userHistory.getPassword(), diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 0d997af2ea..4b6b9138c7 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,29 +32,26 @@ public void insert(final User user) { public void changePassword(final long id, final String newPassword, final String createBy) { final DataSource dataSource = DataSourceConfig.getInstance(); - Connection conn = null; + final Connection conn = DataSourceUtils.getConnection(dataSource); try { - conn = dataSource.getConnection(); + TransactionSynchronizationManager.bindResource(dataSource, conn); conn.setAutoCommit(false); final User user = findById(id); user.changePassword(newPassword); - userDao.update(conn, user); - userHistoryDao.log(conn, new UserHistory(user, createBy)); + userDao.update(user); + userHistoryDao.log(new UserHistory(user, createBy)); conn.commit(); - } catch (SQLException e) { + } catch (Exception e) { try { conn.rollback(); } catch (SQLException exception) { throw new DataAccessException(exception); } } finally { - try { - conn.close(); - } catch (SQLException e) { - throw new DataAccessException(e); - } + DataSourceUtils.releaseConnection(conn, dataSource); + TransactionSynchronizationManager.unbindResource(dataSource); } } } diff --git a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java index 930200453d..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 conn, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { throw new DataAccessException(); } } diff --git a/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java b/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java index 9c801c220f..5f7785c4f7 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java @@ -10,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.DataSourceUtils; abstract class AutoClosableTemplate { @@ -22,16 +23,7 @@ abstract class AutoClosableTemplate { } public void execute(final String sql, final Object... objects) { - try (final Connection conn = dataSource.getConnection(); - final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects) - ) { - commandQuery(pstmt); - } catch (SQLException e) { - throw new DataAccessException(e); - } - } - - public void execute(final Connection conn, final String sql, final Object... objects) { + final Connection conn = DataSourceUtils.getConnection(dataSource); try (final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects)) { commandQuery(pstmt); } catch (SQLException e) { 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..9338161c3f 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -1,16 +1,15 @@ 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 { - private DataSourceUtils() {} + private DataSourceUtils() { + } public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { Connection connection = TransactionSynchronizationManager.getResource(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..3fdaa394a6 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,38 @@ package org.springframework.transaction.support; -import javax.sql.DataSource; import java.sql.Connection; +import java.util.HashMap; import java.util.Map; +import javax.annotation.Nullable; +import javax.sql.DataSource; public abstract class TransactionSynchronizationManager { private static final ThreadLocal> resources = new ThreadLocal<>(); - private TransactionSynchronizationManager() {} + private TransactionSynchronizationManager() { + } + @Nullable public static Connection getResource(DataSource key) { + final Map dataSourceConnMap = resources.get(); + if (dataSourceConnMap != null) { + return dataSourceConnMap.get(key); + } return null; } public static void bindResource(DataSource key, Connection value) { + Map dataSourceConnMap = resources.get(); + if (dataSourceConnMap == null) { + dataSourceConnMap = new HashMap<>(); + resources.set(dataSourceConnMap); + } + dataSourceConnMap.put(key, value); } public static Connection unbindResource(DataSource key) { - return null; + final Map dataSourceConnMap = resources.get(); + return dataSourceConnMap.remove(key); } } From 2b509347036d56888c0c82705f9ef7f6cfa5b71c Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 9 Oct 2023 06:01:14 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20Transaction=20Service=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=ED=99=94?= 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 | 34 ++++++++++++ .../com/techcourse/service/UserService.java | 53 ++----------------- .../techcourse/service/UserServiceTest.java | 18 ++++--- .../support/TransactionExecutor.java | 41 ++++++++++++++ 5 files changed, 124 insertions(+), 57 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/support/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..de9983abce --- /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(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)); + } +} 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..a0fc9c42dd --- /dev/null +++ b/app/src/main/java/com/techcourse/service/TxUserService.java @@ -0,0 +1,34 @@ +package com.techcourse.service; + +import com.techcourse.config.DataSourceConfig; +import com.techcourse.domain.User; +import org.springframework.transaction.support.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 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) { + transactionExecutor.execute(() -> { + userService.changePassword(id, newPassword, createBy); + return null; + }); + } +} diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 4b6b9138c7..b14dbcacbf 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -1,57 +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 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; + User findById(final long id); - public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao) { - this.userDao = userDao; - this.userHistoryDao = userHistoryDao; - } + void insert(final User user); - 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 conn = DataSourceUtils.getConnection(dataSource); - try { - TransactionSynchronizationManager.bindResource(dataSource, conn); - conn.setAutoCommit(false); - - final User user = findById(id); - user.changePassword(newPassword); - - userDao.update(user); - userHistoryDao.log(new UserHistory(user, createBy)); - conn.commit(); - } catch (Exception e) { - try { - conn.rollback(); - } catch (SQLException exception) { - throw new DataAccessException(exception); - } - } finally { - DataSourceUtils.releaseConnection(conn, dataSource); - TransactionSynchronizationManager.unbindResource(dataSource); - } - } + void changePassword(final long id, final String newPassword, final String createBy); } diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index 2d4abce635..d992bbfcee 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -1,18 +1,17 @@ package com.techcourse.service; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + import com.techcourse.config.DataSourceConfig; import com.techcourse.dao.UserDao; import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; class UserServiceTest { @@ -32,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"; @@ -47,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/transaction/support/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java new file mode 100644 index 0000000000..715dfcbe31 --- /dev/null +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java @@ -0,0 +1,41 @@ +package org.springframework.transaction.support; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.function.Supplier; +import javax.sql.DataSource; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.DataSourceUtils; + +public class TransactionExecutor { + + private final DataSource dataSource; + + public TransactionExecutor(DataSource dataSource) { + this.dataSource = dataSource; + } + + public T execute(Supplier supplier) { + final Connection conn = DataSourceUtils.getConnection(dataSource); + try { + conn.setAutoCommit(false); + final T result = supplier.get(); + conn.commit(); + return result; + } catch (Exception e) { + rollback(conn); + throw new DataAccessException(e); + } finally { + DataSourceUtils.releaseConnection(conn, dataSource); + TransactionSynchronizationManager.unbindResource(dataSource); + } + } + + private void rollback(final Connection conn) { + try { + conn.rollback(); + } catch (SQLException exception) { + throw new DataAccessException(exception); + } + } +} From f246759fba285ca925e4f2c2d4e3dc622a9e7b34 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Mon, 9 Oct 2023 06:13:46 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20Executor?= =?UTF-8?q?=20=EC=B6=94=EC=83=81=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/{ => impl}/AppUserService.java | 3 +- .../service/{ => impl}/TxUserService.java | 11 ++--- .../techcourse/service/UserServiceTest.java | 2 + .../transaction/support/ServiceExecutor.java | 40 ++++++++++++++++++ .../support/TransactionExecutor.java | 41 ++----------------- 5 files changed, 53 insertions(+), 44 deletions(-) rename app/src/main/java/com/techcourse/service/{ => impl}/AppUserService.java (92%) rename app/src/main/java/com/techcourse/service/{ => impl}/TxUserService.java (68%) create mode 100644 jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java diff --git a/app/src/main/java/com/techcourse/service/AppUserService.java b/app/src/main/java/com/techcourse/service/impl/AppUserService.java similarity index 92% rename from app/src/main/java/com/techcourse/service/AppUserService.java rename to app/src/main/java/com/techcourse/service/impl/AppUserService.java index de9983abce..6572d3465d 100644 --- a/app/src/main/java/com/techcourse/service/AppUserService.java +++ b/app/src/main/java/com/techcourse/service/impl/AppUserService.java @@ -1,9 +1,10 @@ -package com.techcourse.service; +package com.techcourse.service.impl; import com.techcourse.dao.UserDao; import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; import com.techcourse.domain.UserHistory; +import com.techcourse.service.UserService; public class AppUserService implements UserService { diff --git a/app/src/main/java/com/techcourse/service/TxUserService.java b/app/src/main/java/com/techcourse/service/impl/TxUserService.java similarity index 68% rename from app/src/main/java/com/techcourse/service/TxUserService.java rename to app/src/main/java/com/techcourse/service/impl/TxUserService.java index a0fc9c42dd..4e9c63205a 100644 --- a/app/src/main/java/com/techcourse/service/TxUserService.java +++ b/app/src/main/java/com/techcourse/service/impl/TxUserService.java @@ -1,17 +1,18 @@ -package com.techcourse.service; +package com.techcourse.service.impl; import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.User; -import org.springframework.transaction.support.TransactionExecutor; +import com.techcourse.service.UserService; +import org.springframework.transaction.support.ServiceExecutor; public class TxUserService implements UserService { private final UserService userService; - private final TransactionExecutor transactionExecutor; + private final ServiceExecutor serviceExecutor; public TxUserService(final UserService userService) { this.userService = userService; - this.transactionExecutor = new TransactionExecutor(DataSourceConfig.getInstance()); + this.serviceExecutor = new ServiceExecutor(DataSourceConfig.getInstance()); } @Override @@ -26,7 +27,7 @@ public void insert(final User user) { @Override public void changePassword(final long id, final String newPassword, final String createBy) { - transactionExecutor.execute(() -> { + serviceExecutor.execute(() -> { userService.changePassword(id, newPassword, createBy); return null; }); diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index d992bbfcee..c58d811662 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -7,6 +7,8 @@ import com.techcourse.dao.UserDao; import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; +import com.techcourse.service.impl.AppUserService; +import com.techcourse.service.impl.TxUserService; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java b/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java new file mode 100644 index 0000000000..9aa1116bfb --- /dev/null +++ b/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java @@ -0,0 +1,40 @@ +package org.springframework.transaction.support; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.datasource.DataSourceUtils; + +public class ServiceExecutor { + + private final DataSource dataSource; + + public ServiceExecutor(DataSource dataSource) { + this.dataSource = dataSource; + } + + public T execute(TransactionExecutor executor) { + final Connection conn = DataSourceUtils.getConnection(dataSource); + try { + conn.setAutoCommit(false); + final T result = executor.execute(); + conn.commit(); + return result; + } catch (Exception e) { + rollback(conn); + throw new DataAccessException(e); + } finally { + DataSourceUtils.releaseConnection(conn, dataSource); + TransactionSynchronizationManager.unbindResource(dataSource); + } + } + + private void rollback(final Connection conn) { + try { + conn.rollback(); + } catch (SQLException exception) { + throw new DataAccessException(exception); + } + } +} diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java index 715dfcbe31..d54088756b 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java @@ -1,41 +1,6 @@ package org.springframework.transaction.support; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.function.Supplier; -import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.datasource.DataSourceUtils; - -public class TransactionExecutor { - - private final DataSource dataSource; - - public TransactionExecutor(DataSource dataSource) { - this.dataSource = dataSource; - } - - public T execute(Supplier supplier) { - final Connection conn = DataSourceUtils.getConnection(dataSource); - try { - conn.setAutoCommit(false); - final T result = supplier.get(); - conn.commit(); - return result; - } catch (Exception e) { - rollback(conn); - throw new DataAccessException(e); - } finally { - DataSourceUtils.releaseConnection(conn, dataSource); - TransactionSynchronizationManager.unbindResource(dataSource); - } - } - - private void rollback(final Connection conn) { - try { - conn.rollback(); - } catch (SQLException exception) { - throw new DataAccessException(exception); - } - } +@FunctionalInterface +public interface TransactionExecutor { + T execute(); } From 8edf972678aae109899465c4c3a51410a0e25f63 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Tue, 10 Oct 2023 13:12:46 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20null=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EC=9D=BC=EA=B4=80=EC=84=B1=EC=9E=88=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../support/TransactionSynchronizationManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 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 3fdaa394a6..1e5e080393 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -16,10 +16,10 @@ private TransactionSynchronizationManager() { @Nullable public static Connection getResource(DataSource key) { final Map dataSourceConnMap = resources.get(); - if (dataSourceConnMap != null) { - return dataSourceConnMap.get(key); + if (dataSourceConnMap == null) { + return null; } - return null; + return dataSourceConnMap.get(key); } public static void bindResource(DataSource key, Connection value) { From 68bc2960183f0d18d990c565c1e4a757e84af973 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Tue, 10 Oct 2023 13:14:23 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20resource=20=EB=AF=B8=EB=A6=AC?= =?UTF-8?q?=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EB=B0=8F=20unbind=EC=8B=9C=20?= =?UTF-8?q?remove=20=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 --- .../support/TransactionSynchronizationManager.java | 6 ++++-- 1 file changed, 4 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 1e5e080393..768c0689b0 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -8,7 +8,7 @@ public abstract class TransactionSynchronizationManager { - private static final ThreadLocal> resources = new ThreadLocal<>(); + private static final ThreadLocal> resources = ThreadLocal.withInitial(HashMap::new); private TransactionSynchronizationManager() { } @@ -33,6 +33,8 @@ public static void bindResource(DataSource key, Connection value) { public static Connection unbindResource(DataSource key) { final Map dataSourceConnMap = resources.get(); - return dataSourceConnMap.remove(key); + final Connection removedConn = dataSourceConnMap.remove(key); + resources.remove(); + return removedConn; } } From f6b8c25fa318fbcdedc44b26724cd532a3cd0607 Mon Sep 17 00:00:00 2001 From: jjongwa Date: Tue, 10 Oct 2023 13:47:51 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20query=EC=99=80=20queryForObject?= =?UTF-8?q?=EC=97=90=EC=84=9C=EB=8F=84=20=EB=8F=99=EC=9D=BC=ED=95=9C=20con?= =?UTF-8?q?nection=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=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 --- .../jdbc/core/AutoClosableTemplate.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java b/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java index 5f7785c4f7..3d422aeac6 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/AutoClosableTemplate.java @@ -32,9 +32,8 @@ public void execute(final String sql, final Object... objects) { } public List query(final String sql, final RowMapper rowMapper, final Object... objects) { - try (final Connection conn = dataSource.getConnection(); - final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects) - ) { + final Connection conn = DataSourceUtils.getConnection(dataSource); + try (final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects)) { final ResultSet rs = pstmt.executeQuery(); return queryAll(rs, rowMapper); } catch (SQLException e) { @@ -44,9 +43,8 @@ public List query(final String sql, final RowMapper rowMapper, final O @Nullable public T queryForObject(final String sql, final RowMapper rowMapper, final Object... objects) { - try (final Connection conn = dataSource.getConnection(); - final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects) - ) { + final Connection conn = DataSourceUtils.getConnection(dataSource); + try (final PreparedStatement pstmt = preparedStatementAndSetValue(conn, sql, objects)) { final ResultSet rs = pstmt.executeQuery(); return queryForOne(rs, rowMapper); } catch (SQLException e) { From 17c90518ff8e57b6410717453dcb4418e834535f Mon Sep 17 00:00:00 2001 From: jjongwa Date: Tue, 10 Oct 2023 13:51:31 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../springframework/transaction/support/ServiceExecutor.java | 2 +- .../{TransactionExecutor.java => TransactionTemplate.java} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename jdbc/src/main/java/org/springframework/transaction/support/{TransactionExecutor.java => TransactionTemplate.java} (68%) diff --git a/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java b/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java index 9aa1116bfb..765dcd29ed 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/ServiceExecutor.java @@ -14,7 +14,7 @@ public ServiceExecutor(DataSource dataSource) { this.dataSource = dataSource; } - public T execute(TransactionExecutor executor) { + public T execute(TransactionTemplate executor) { final Connection conn = DataSourceUtils.getConnection(dataSource); try { conn.setAutoCommit(false); diff --git a/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java b/jdbc/src/main/java/org/springframework/transaction/support/TransactionTemplate.java similarity index 68% rename from jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java rename to jdbc/src/main/java/org/springframework/transaction/support/TransactionTemplate.java index d54088756b..56490cba88 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionTemplate.java @@ -1,6 +1,6 @@ package org.springframework.transaction.support; @FunctionalInterface -public interface TransactionExecutor { +public interface TransactionTemplate { T execute(); }