From f97f2f9bd8dc21f7f9af2f6e6a598041f1bb3c0b Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Tue, 10 Oct 2023 13:21:16 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=203=EB=8B=A8=EA=B3=84=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81=20-=20null=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20=EC=B1=85=EC=9E=84=EC=9D=84=20service=EC=97=90?= =?UTF-8?q?=EC=84=9C=EB=A7=8C=20=EC=88=98=ED=96=89=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../techcourse/dao/UserDaoWithJdbcTemplate.java | 16 ++++------------ .../UserDaoWithNamedParameterJdbcTemplate.java | 16 ++++------------ .../techcourse/repository/UserRepository.java | 5 +++-- .../java/com/techcourse/service/UserService.java | 7 ++++++- .../dao/UserDaoWithJdbcTemplateTest.java | 10 +++++----- ...serDaoWithNamedParameterJdbcTemplateTest.java | 10 +++++----- 6 files changed, 27 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java b/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java index 944f8d6705..0ead49e0a7 100644 --- a/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java +++ b/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java @@ -32,22 +32,14 @@ public List findAll(final Connection connection) { return jdbcTemplate.query(connection, sql, getUserRowMapper()); } - public User findById(final Connection connection, final Long id) { + public Optional findById(final Connection connection, final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - final Optional user = jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), id); - if (user.isEmpty()) { - throw new RuntimeException("유저 없음!"); - } - return user.get(); + return jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), id); } - public User findByAccount(final Connection connection, final String account) { + public Optional findByAccount(final Connection connection, final String account) { final var sql = "select id, account, password, email from users where account = ?"; - final Optional user = jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), account); - if (user.isEmpty()) { - throw new RuntimeException("유저 없음!"); - } - return user.get(); + return jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), account); } private static RowMapper getUserRowMapper() { diff --git a/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java b/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java index 4043d1836a..d2607bcc7b 100644 --- a/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java +++ b/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java @@ -40,26 +40,18 @@ public List findAll() { return jdbcTemplate.query(sql, getUserRowMapper(), Map.of()); } - public User findById(final Long id) { + public Optional findById(final Long id) { final var sql = "select id, account, password, email from users where id = :id"; final HashMap parameters = new HashMap<>(); parameters.put("id", id); - final Optional user = jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); - if (user.isEmpty()) { - throw new RuntimeException("유저 없음!"); - } - return user.get(); + return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); } - public User findByAccount(final String account) { + public Optional findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = :account"; final HashMap parameters = new HashMap<>(); parameters.put("account", account); - final Optional user = jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); - if (user.isEmpty()) { - throw new RuntimeException("유저 없음!"); - } - return user.get(); + return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); } private static RowMapper getUserRowMapper() { diff --git a/app/src/main/java/com/techcourse/repository/UserRepository.java b/app/src/main/java/com/techcourse/repository/UserRepository.java index 97f76eb402..20fbce4eda 100644 --- a/app/src/main/java/com/techcourse/repository/UserRepository.java +++ b/app/src/main/java/com/techcourse/repository/UserRepository.java @@ -3,6 +3,7 @@ import com.techcourse.domain.User; import java.sql.Connection; import java.util.List; +import java.util.Optional; public interface UserRepository { @@ -12,7 +13,7 @@ public interface UserRepository { List findAll(final Connection connection); - User findById(final Connection connection, final Long id); + Optional findById(final Connection connection, final Long id); - User findByAccount(final Connection connection, final String account); + Optional findByAccount(final Connection connection, final String account); } diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 627fb5a6aa..45ba285975 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -6,6 +6,7 @@ import com.techcourse.domain.UserHistory; import java.sql.Connection; import java.sql.SQLException; +import java.util.Optional; import org.springframework.dao.DataAccessException; import org.springframework.dao.SQLTransactionRollbackException; @@ -22,7 +23,11 @@ public UserService(final Connection connection, final UserDaoWithJdbcTemplate us } public User findById(final long id) { - return userDao.findById(connection, id); + final Optional user = userDao.findById(connection, id); + if (user.isEmpty()) { + throw new IllegalArgumentException("회원을 찾을 수 없음"); + } + return user.get(); } public void insert(final User user) { diff --git a/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java b/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java index 8118ad6faa..730a5970c6 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java @@ -43,7 +43,7 @@ void findAll() { @Test void findById() { final long savedUserId = userDao.findAll(connection).get(0).getId(); - final var user = userDao.findById(connection, savedUserId); + final var user = userDao.findById(connection, savedUserId).get(); assertThat(user.getAccount()).isEqualTo("gugu"); } @@ -52,7 +52,7 @@ void findById() { void findByAccount() { final var account = "gugu"; - final var user = userDao.findByAccount(connection, account); + final var user = userDao.findByAccount(connection, account).get(); assertThat(user.getAccount()).isEqualTo(account); } @@ -71,7 +71,7 @@ void insert() { final var user = new User(account, "password", "hkkang@woowahan.com"); userDao.insert(connection, user); - final var actual = userDao.findById(connection, 2L); + final var actual = userDao.findById(connection, 2L).get(); assertThat(actual.getAccount()).isEqualTo(account); } @@ -81,12 +81,12 @@ void update() { final var newPassword = "password99"; final long savedUserId = userDao.findAll(connection).get(0).getId(); - final var user = userDao.findById(connection, savedUserId); + final var user = userDao.findById(connection, savedUserId).get(); user.changePassword(newPassword); userDao.update(connection, user); - final var actual = userDao.findById(connection, savedUserId); + final var actual = userDao.findById(connection, savedUserId).get(); assertThat(actual.getPassword()).isEqualTo(newPassword); } diff --git a/app/src/test/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplateTest.java b/app/src/test/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplateTest.java index c5332602cc..13a8d81b70 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplateTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplateTest.java @@ -40,7 +40,7 @@ void findAll() { @Test void findById() { final long savedUserId = userDao.findAll().get(0).getId(); - final var user = userDao.findById(savedUserId); + final var user = userDao.findById(savedUserId).get(); assertThat(user.getAccount()).isEqualTo("gugu"); } @@ -48,7 +48,7 @@ void findById() { @Test void findByAccount() { final var account = "gugu"; - final var user = userDao.findByAccount(account); + final var user = userDao.findByAccount(account).get(); assertThat(user.getAccount()).isEqualTo(account); } @@ -67,7 +67,7 @@ void insert() { final var user = new User(account, "password", "hkkang@woowahan.com"); userDao.insert(user); - final var actual = userDao.findById(2L); + final var actual = userDao.findById(2L).get(); assertThat(actual.getAccount()).isEqualTo(account); } @@ -76,12 +76,12 @@ void insert() { void update() { final var newPassword = "password99"; final long savedUserId = userDao.findAll().get(0).getId(); - final var user = userDao.findById(savedUserId); + final var user = userDao.findById(savedUserId).get(); user.changePassword(newPassword); userDao.update(user); - final var actual = userDao.findById(savedUserId); + final var actual = userDao.findById(savedUserId).get(); assertThat(actual.getPassword()).isEqualTo(newPassword); } From d29b6ffff95bcb569265a9f7643cbc5005950fd1 Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Tue, 10 Oct 2023 13:30:15 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=203=EB=8B=A8=EA=B3=84=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81=20-=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EC=98=88=EC=99=B8=20=EB=B0=9C=EC=83=9D?= =?UTF-8?q?=EC=8B=9C=20DataAccessException=20=EB=8C=80=EC=8B=A0=20RuntimeE?= =?UTF-8?q?xception=20=EB=8D=98=EC=A7=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/techcourse/service/UserService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 45ba285975..e56f1c8e50 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -7,7 +7,6 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Optional; -import org.springframework.dao.DataAccessException; import org.springframework.dao.SQLTransactionRollbackException; public class UserService { @@ -52,7 +51,7 @@ public void changePassword(final long id, final String newPassword, final String private void handleTransactionFailure(final Exception e) { try { connection.rollback(); - throw new DataAccessException(e); + throw new RuntimeException(e); } catch (SQLException ex) { throw new SQLTransactionRollbackException(ex); } From dc40b02a1ffda3121aa4e7ff6a4cc82ab79c9274 Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Tue, 10 Oct 2023 16:05:13 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=204=EB=8B=A8=EA=B3=84=20-=20DataS?= =?UTF-8?q?ourceUtils=EB=A5=BC=20=EA=B5=AC=ED=98=84=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=ED=95=B5=EC=8B=AC=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jdbc/datasource/DataSourceUtilsTest.java | 28 +++++++++++++++++++ .../TransactionSynchronizationManager.java | 24 ++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 app/src/test/java/com/techcourse/jdbc/datasource/DataSourceUtilsTest.java diff --git a/app/src/test/java/com/techcourse/jdbc/datasource/DataSourceUtilsTest.java b/app/src/test/java/com/techcourse/jdbc/datasource/DataSourceUtilsTest.java new file mode 100644 index 0000000000..7e30219bd9 --- /dev/null +++ b/app/src/test/java/com/techcourse/jdbc/datasource/DataSourceUtilsTest.java @@ -0,0 +1,28 @@ +package com.techcourse.jdbc.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.techcourse.config.DataSourceConfig; +import java.sql.Connection; +import javax.sql.DataSource; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.datasource.DataSourceUtils; + +class DataSourceUtilsTest { + + @Test + @DisplayName("DataSourceUtils를 이용해 커넥션을 가져올 수 있다.") + void getConnection() { + final DataSource dataSource = DataSourceConfig.getInstance(); + final Connection connection = DataSourceUtils.getConnection(dataSource); + assertThat(connection) + .as("기존 커넥션이 없다면 새로 만들어 가져오고,") + .isNotNull(); + + final Connection connection2 = DataSourceUtils.getConnection(dataSource); + assertThat(connection) + .as("기존 커넥션이 있다면 등록된 커넥션을 가져온다.") + .isSameAs(connection2); + } +} 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..b8b6e5c585 100644 --- a/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java +++ b/jdbc/src/main/java/org/springframework/transaction/support/TransactionSynchronizationManager.java @@ -1,5 +1,8 @@ package org.springframework.transaction.support; +import java.util.HashMap; +import java.util.Objects; +import javax.annotation.Nullable; import javax.sql.DataSource; import java.sql.Connection; import java.util.Map; @@ -8,16 +11,31 @@ public abstract class TransactionSynchronizationManager { private static final ThreadLocal> resources = new ThreadLocal<>(); - private TransactionSynchronizationManager() {} + private TransactionSynchronizationManager() { + } + @Nullable public static Connection getResource(DataSource key) { - return null; + final Map dataSourceConnectionEntry = resources.get(); + if (Objects.isNull(dataSourceConnectionEntry)) { + return null; + } + return dataSourceConnectionEntry.get(key); } public static void bindResource(DataSource key, Connection value) { + final Map dataSourceConnectionEntry = resources.get(); + if (Objects.isNull(dataSourceConnectionEntry)) { + resources.set(new HashMap<>()); + } + resources.get().put(key, value); } public static Connection unbindResource(DataSource key) { - return null; + return resources.get().remove(key); + } + + public static void remove() { + resources.remove(); } } From 084d77303b0b8aee2af87e07326e80bc8b9ea78e Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Tue, 10 Oct 2023 16:49:23 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=204=EB=8B=A8=EA=B3=84=20-=20DataS?= =?UTF-8?q?ourceUtils=EB=A5=BC=20=ED=99=9C=EC=9A=A9=ED=95=B4=20DAO?= =?UTF-8?q?=EC=99=80=20Service=EA=B0=80=20Connection=EC=9D=84=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dao/UserDaoWithJdbcTemplate.java | 26 +++++++------ ...UserDaoWithNamedParameterJdbcTemplate.java | 38 ++++++++++++------- .../com/techcourse/dao/UserHistoryDao.java | 6 +-- .../techcourse/repository/UserRepository.java | 11 +++--- .../com/techcourse/service/UserService.java | 24 +++++++----- .../dao/UserDaoWithJdbcTemplateTest.java | 32 +++++++--------- .../techcourse/dao/UserHistoryDaoTest.java | 8 +--- .../service/MockUserHistoryDao.java | 3 +- .../techcourse/service/UserServiceTest.java | 16 +++----- .../jdbc/core/JdbcTemplate.java | 10 +++-- .../jdbc/datasource/DataSourceUtils.java | 16 +++++--- 11 files changed, 102 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java b/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java index 0ead49e0a7..32586d501c 100644 --- a/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java +++ b/app/src/main/java/com/techcourse/dao/UserDaoWithJdbcTemplate.java @@ -2,7 +2,6 @@ import com.techcourse.domain.User; import com.techcourse.repository.UserRepository; -import java.sql.Connection; import java.util.List; import java.util.Optional; import javax.sql.DataSource; @@ -17,29 +16,34 @@ public UserDaoWithJdbcTemplate(final DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } - public void insert(final Connection connection, final User user) { + @Override + public void insert(final User user) { final var sql = "insert into users (account, password, email) values (?, ?, ?)"; - jdbcTemplate.update(connection, sql, user.getAccount(), user.getPassword(), user.getEmail()); + jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail()); } - public void update(final Connection connection, final User user) { + @Override + public void update(final User user) { final String sql = "update users set (account, password, email) = (?, ?, ?) where id = ?"; - jdbcTemplate.update(connection, sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); + jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId()); } - public List findAll(final Connection connection) { + @Override + public List findAll() { final String sql = "select * from users"; - return jdbcTemplate.query(connection, sql, getUserRowMapper()); + return jdbcTemplate.query(sql, getUserRowMapper()); } - public Optional findById(final Connection connection, final Long id) { + @Override + public Optional findById(final Long id) { final var sql = "select id, account, password, email from users where id = ?"; - return jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), id); + return jdbcTemplate.queryForObject(sql, getUserRowMapper(), id); } - public Optional findByAccount(final Connection connection, final String account) { + @Override + public Optional findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = ?"; - return jdbcTemplate.queryForObject(connection, sql, getUserRowMapper(), account); + return jdbcTemplate.queryForObject(sql, getUserRowMapper(), account); } private static RowMapper getUserRowMapper() { diff --git a/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java b/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java index d2607bcc7b..e414d3ec46 100644 --- a/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java +++ b/app/src/main/java/com/techcourse/dao/UserDaoWithNamedParameterJdbcTemplate.java @@ -1,6 +1,7 @@ package com.techcourse.dao; import com.techcourse.domain.User; +import com.techcourse.repository.UserRepository; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -9,56 +10,65 @@ import org.springframework.jdbc.core.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.RowMapper; -public class UserDaoWithNamedParameterJdbcTemplate { +public class UserDaoWithNamedParameterJdbcTemplate implements UserRepository { + public static final String ACCOUNT = "account"; + public static final String PASSWORD = "password"; + public static final String EMAIL = "email"; + public static final String ID = "id"; private final NamedParameterJdbcTemplate jdbcTemplate; public UserDaoWithNamedParameterJdbcTemplate(final DataSource dataSource) { this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource); } + @Override public void insert(final User user) { final var sql = "insert into users (account, password, email) values (:account, :password, :email)"; final HashMap parameters = new HashMap<>(); - parameters.put("account", user.getAccount()); - parameters.put("password", user.getPassword()); - parameters.put("email", user.getEmail()); + parameters.put(ACCOUNT, user.getAccount()); + parameters.put(PASSWORD, user.getPassword()); + parameters.put(EMAIL, user.getEmail()); jdbcTemplate.update(sql, parameters); } + @Override public void update(final User user) { final String sql = "update users set (account, password, email) = (:account, :password, :email) where id = :id"; final HashMap parameters = new HashMap<>(); - parameters.put("account", user.getAccount()); - parameters.put("password", user.getPassword()); - parameters.put("email", user.getEmail()); - parameters.put("id", user.getId()); + parameters.put(ACCOUNT, user.getAccount()); + parameters.put(PASSWORD, user.getPassword()); + parameters.put(EMAIL, user.getEmail()); + parameters.put(ID, user.getId()); jdbcTemplate.update(sql, parameters); } + @Override public List findAll() { final String sql = "select * from users"; return jdbcTemplate.query(sql, getUserRowMapper(), Map.of()); } + @Override public Optional findById(final Long id) { final var sql = "select id, account, password, email from users where id = :id"; final HashMap parameters = new HashMap<>(); - parameters.put("id", id); + parameters.put(ID, id); return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); } + @Override public Optional findByAccount(final String account) { final var sql = "select id, account, password, email from users where account = :account"; final HashMap parameters = new HashMap<>(); - parameters.put("account", account); + parameters.put(ACCOUNT, account); return jdbcTemplate.queryForObject(sql, getUserRowMapper(), parameters); } private static RowMapper getUserRowMapper() { return (rs, rowNum) -> new User( - rs.getLong("id"), - rs.getString("account"), - rs.getString("password"), - rs.getString("email")); + rs.getLong(ID), + rs.getString(ACCOUNT), + rs.getString(PASSWORD), + rs.getString(EMAIL)); } } diff --git a/app/src/main/java/com/techcourse/dao/UserHistoryDao.java b/app/src/main/java/com/techcourse/dao/UserHistoryDao.java index 27bf9f3ffb..f88c89e5ce 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; import javax.sql.DataSource; @@ -14,10 +13,9 @@ public UserHistoryDao(final DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } - 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(), diff --git a/app/src/main/java/com/techcourse/repository/UserRepository.java b/app/src/main/java/com/techcourse/repository/UserRepository.java index 20fbce4eda..52cc883cbf 100644 --- a/app/src/main/java/com/techcourse/repository/UserRepository.java +++ b/app/src/main/java/com/techcourse/repository/UserRepository.java @@ -1,19 +1,18 @@ package com.techcourse.repository; import com.techcourse.domain.User; -import java.sql.Connection; import java.util.List; import java.util.Optional; public interface UserRepository { - void insert(final Connection connection, final User user); + void insert(final User user); - void update(final Connection connection, final User user); + void update(final User user); - List findAll(final Connection connection); + List findAll(); - Optional findById(final Connection connection, final Long id); + Optional findById(final Long id); - Optional findByAccount(final Connection connection, final String account); + Optional findByAccount(final String account); } diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index e56f1c8e50..61a9f5c26a 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -1,5 +1,6 @@ package com.techcourse.service; +import com.techcourse.config.DataSourceConfig; import com.techcourse.dao.UserDaoWithJdbcTemplate; import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; @@ -7,22 +8,24 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.Optional; +import javax.sql.DataSource; import org.springframework.dao.SQLTransactionRollbackException; +import org.springframework.jdbc.datasource.DataSourceUtils; public class UserService { private final UserDaoWithJdbcTemplate userDao; private final UserHistoryDao userHistoryDao; - private final Connection connection; + private final DataSource dataSource; - public UserService(final Connection connection, final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) { - this.connection = connection; + public UserService(final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) { + this.dataSource = DataSourceConfig.getInstance(); this.userDao = userDao; this.userHistoryDao = userHistoryDao; } public User findById(final long id) { - final Optional user = userDao.findById(connection, id); + final Optional user = userDao.findById(id); if (user.isEmpty()) { throw new IllegalArgumentException("회원을 찾을 수 없음"); } @@ -30,25 +33,28 @@ public User findById(final long id) { } public void insert(final User user) { - userDao.insert(connection, user); + userDao.insert(user); } public void changePassword(final long id, final String newPassword, final String createBy) { + 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)); + userDao.update(user); + userHistoryDao.log(new UserHistory(user, createBy)); connection.commit(); } catch (RuntimeException | SQLException e) { - handleTransactionFailure(e); + handleTransactionFailure(connection, e); + } finally { + DataSourceUtils.releaseConnection(connection, dataSource); } } - private void handleTransactionFailure(final Exception e) { + private void handleTransactionFailure(final Connection connection, final Exception e) { try { connection.rollback(); throw new RuntimeException(e); diff --git a/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java b/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java index 730a5970c6..426e108dbd 100644 --- a/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java +++ b/app/src/test/java/com/techcourse/dao/UserDaoWithJdbcTemplateTest.java @@ -3,8 +3,6 @@ import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.User; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; -import java.sql.Connection; -import java.sql.SQLException; import java.util.Map; import javax.sql.DataSource; import org.junit.jupiter.api.AfterEach; @@ -19,31 +17,29 @@ class UserDaoWithJdbcTemplateTest { private UserDaoWithJdbcTemplate userDao; private NamedParameterJdbcTemplate namedParameterJdbcTemplate; - private Connection connection; @BeforeEach - void setup() throws SQLException { + void setup() { final DataSource dataSource = DataSourceConfig.getInstance(); DatabasePopulatorUtils.execute(dataSource); - connection = dataSource.getConnection(); userDao = new UserDaoWithJdbcTemplate(dataSource); namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); final var user = new User("gugu", "password", "hkkang@woowahan.com"); - userDao.insert(connection, user); + userDao.insert(user); } @Test void findAll() { - final var users = userDao.findAll(connection); + final var users = userDao.findAll(); assertThat(users).isNotEmpty(); } @Test void findById() { - final long savedUserId = userDao.findAll(connection).get(0).getId(); - final var user = userDao.findById(connection, savedUserId).get(); + final long savedUserId = userDao.findAll().get(0).getId(); + final var user = userDao.findById(savedUserId).get(); assertThat(user.getAccount()).isEqualTo("gugu"); } @@ -52,16 +48,16 @@ void findById() { void findByAccount() { final var account = "gugu"; - final var user = userDao.findByAccount(connection, account).get(); + final var user = userDao.findByAccount(account).get(); assertThat(user.getAccount()).isEqualTo(account); } @Test void findByAccountIncorrectColumnSize() { - userDao.insert(connection, new User("gugu", "password", "hkkang@woowahan.com")); + userDao.insert(new User("gugu", "password", "hkkang@woowahan.com")); - assertThatThrownBy(() -> userDao.findByAccount(connection, "gugu")) + assertThatThrownBy(() -> userDao.findByAccount("gugu")) .hasMessageContaining("결과가 1개인 줄 알았는데, 2개 나왔서!"); } @@ -69,9 +65,9 @@ void findByAccountIncorrectColumnSize() { void insert() { final var account = "insert-gugu"; final var user = new User(account, "password", "hkkang@woowahan.com"); - userDao.insert(connection, user); + userDao.insert(user); - final var actual = userDao.findById(connection, 2L).get(); + final var actual = userDao.findById(2L).get(); assertThat(actual.getAccount()).isEqualTo(account); } @@ -79,14 +75,14 @@ void insert() { @Test void update() { final var newPassword = "password99"; - final long savedUserId = userDao.findAll(connection).get(0).getId(); + final long savedUserId = userDao.findAll().get(0).getId(); - final var user = userDao.findById(connection, savedUserId).get(); + final var user = userDao.findById(savedUserId).get(); user.changePassword(newPassword); - userDao.update(connection, user); + userDao.update(user); - final var actual = userDao.findById(connection, savedUserId).get(); + final var actual = userDao.findById(savedUserId).get(); assertThat(actual.getPassword()).isEqualTo(newPassword); } diff --git a/app/src/test/java/com/techcourse/dao/UserHistoryDaoTest.java b/app/src/test/java/com/techcourse/dao/UserHistoryDaoTest.java index 261d05eb77..53197a8a9a 100644 --- a/app/src/test/java/com/techcourse/dao/UserHistoryDaoTest.java +++ b/app/src/test/java/com/techcourse/dao/UserHistoryDaoTest.java @@ -5,8 +5,6 @@ import com.techcourse.config.DataSourceConfig; import com.techcourse.domain.UserHistory; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; -import java.sql.Connection; -import java.sql.SQLException; import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,19 +12,17 @@ class UserHistoryDaoTest { private UserHistoryDao userHistoryDao; - private Connection connection; @BeforeEach - void setup() throws SQLException { + void setup() { final DataSource dataSource = DataSourceConfig.getInstance(); DatabasePopulatorUtils.execute(dataSource); this.userHistoryDao = new UserHistoryDao(DataSourceConfig.getInstance()); - this.connection = dataSource.getConnection(); } @Test void savingUserHistory() { - assertThatCode(() -> userHistoryDao.log(connection, new UserHistory(1L, 1L, "account", "password", "email", "now"))) + assertThatCode(() -> userHistoryDao.log(new UserHistory(1L, 1L, "account", "password", "email", "now"))) .doesNotThrowAnyException(); } } diff --git a/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java b/app/src/test/java/com/techcourse/service/MockUserHistoryDao.java index 1168fb00bd..64ee72882b 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 javax.sql.DataSource; import org.springframework.dao.DataAccessException; @@ -13,7 +12,7 @@ public MockUserHistoryDao(final DataSource dataSource) { } @Override - public void log(final Connection connection, final UserHistory userHistory) { + public void log(final UserHistory userHistory) { throw new DataAccessException(); } } diff --git a/app/src/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index cb51f34d02..8ee3c3d3b3 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -8,39 +8,35 @@ import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; -import java.sql.Connection; -import java.sql.SQLException; import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.dao.DataAccessException; class UserServiceTest { private DataSource dataSource; private UserDaoWithJdbcTemplate userDao; - private Connection connection; @BeforeEach - void setUp() throws SQLException { + void setUp() { this.dataSource = DataSourceConfig.getInstance(); this.userDao = new UserDaoWithJdbcTemplate(DataSourceConfig.getInstance()); - this.connection = dataSource.getConnection(); DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); final var user = new User("gugu", "password", "hkkang@woowahan.com"); - userDao.insert(connection, user); + userDao.insert(user); } @Test void testChangePassword() { final var userHistoryDao = new UserHistoryDao(dataSource); - final var userService = new UserService(connection, userDao, userHistoryDao); + final var userService = new UserService(userDao, userHistoryDao); final var newPassword = "qqqqq"; final var createBy = "gugu"; userService.changePassword(1L, newPassword, createBy); + // 서비스의 메서드 호출이 끝나면서 커넥션이 닫혔으므로, 새 서비스 클래스를 만들어야 한다. final var actual = userService.findById(1L); assertThat(actual.getPassword()).isEqualTo(newPassword); @@ -50,12 +46,12 @@ void testChangePassword() { void testTransactionRollback() { // 트랜잭션 롤백 테스트를 위해 mock으로 교체 final var userHistoryDao = new MockUserHistoryDao(dataSource); - final var userService = new UserService(connection, userDao, userHistoryDao); + final var userService = new UserService(userDao, userHistoryDao); final var newPassword = "newPassword"; final var createBy = "gugu"; // 트랜잭션이 정상 동작하는지 확인하기 위해 의도적으로 MockUserHistoryDao에서 예외를 발생시킨다. - assertThrows(DataAccessException.class, + assertThrows(RuntimeException.class, () -> userService.changePassword(1L, newPassword, createBy)); final var actual = userService.findById(1L); 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 4d53fd1e1b..9bd5e5180b 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -12,6 +12,7 @@ import javax.sql.DataSource; import org.springframework.dao.SQLExceptionTranslator; +import org.springframework.jdbc.datasource.DataSourceUtils; public class JdbcTemplate { @@ -23,7 +24,8 @@ public JdbcTemplate(final DataSource dataSource) { this.dataSource = dataSource; } - public int update(Connection connection, String sql, Object... parameters) { + public int update(String sql, Object... parameters) { + final Connection connection = DataSourceUtils.getConnection(dataSource); try ( PreparedStatement pstmt = connection.prepareStatement(sql); ) { @@ -36,7 +38,8 @@ public int update(Connection connection, String sql, Object... parameters) { } } - public Optional queryForObject(Connection connection, String sql, RowMapper rowMapper, Object... parameters) { + public Optional queryForObject(String sql, RowMapper rowMapper, Object... parameters) { + final Connection connection = DataSourceUtils.getConnection(dataSource); try ( PreparedStatement pstmt = connection.prepareStatement(sql); ) { @@ -68,7 +71,8 @@ private static void verifyResultRowSize(final ResultSet rs, final int rowSize) t } } - public List query(Connection connection, String sql, RowMapper rowMapper, Object... parameters) { + public List query(String sql, RowMapper rowMapper, Object... parameters) { + final Connection connection = DataSourceUtils.getConnection(dataSource); try ( PreparedStatement pstmt = connection.prepareStatement(sql); ) { 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..d1b18e9b97 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java +++ b/jdbc/src/main/java/org/springframework/jdbc/datasource/DataSourceUtils.java @@ -1,26 +1,30 @@ 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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.CannotGetJdbcConnectionException; +import org.springframework.transaction.support.TransactionSynchronizationManager; -// 4단계 미션에서 사용할 것 public abstract class DataSourceUtils { + private static final Logger log = LoggerFactory.getLogger(DataSourceUtils.class.getName()); + private DataSourceUtils() {} public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { Connection connection = TransactionSynchronizationManager.getResource(dataSource); if (connection != null) { + log.info("존재하는 Connection 반환 - {}", connection); return connection; } try { connection = dataSource.getConnection(); TransactionSynchronizationManager.bindResource(dataSource, connection); + log.info("새로 만든 Connection 반환 - {}", connection); return connection; } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", ex); @@ -30,6 +34,8 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd public static void releaseConnection(Connection connection, DataSource dataSource) { try { connection.close(); + TransactionSynchronizationManager.unbindResource(dataSource); + log.info("Connection 종료 - {}", connection); } catch (SQLException ex) { throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection"); } From 74acc1046d029a185e562140daa70d3a255777e7 Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Tue, 10 Oct 2023 17:11:02 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=204=EB=8B=A8=EA=B3=84=20-=20JDK?= =?UTF-8?q?=20Dynamic=20Proxy=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=B4=20Use?= =?UTF-8?q?rService=EB=A5=BC=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=B2=A0?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EA=B4=80=EB=A0=A8=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=EA=B3=BC=20=EC=99=84=EC=A0=84=ED=9E=88=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/TransactionProxyHandler.java | 45 ++++++++++++++ .../com/techcourse/service/UserService.java | 62 ++----------------- .../techcourse/service/UserServiceImpl.java | 40 ++++++++++++ .../techcourse/service/UserServiceTest.java | 11 +++- 4 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/com/techcourse/service/TransactionProxyHandler.java create mode 100644 app/src/main/java/com/techcourse/service/UserServiceImpl.java diff --git a/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java b/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java new file mode 100644 index 0000000000..58a15be435 --- /dev/null +++ b/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java @@ -0,0 +1,45 @@ +package com.techcourse.service; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; +import org.springframework.dao.SQLTransactionRollbackException; +import org.springframework.jdbc.datasource.DataSourceUtils; + +public class TransactionProxyHandler implements InvocationHandler { + + private final Object target; + private final DataSource dataSource; + + public TransactionProxyHandler(final Object target, final DataSource dataSource) { + this.target = target; + this.dataSource = dataSource; + } + + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + final Connection connection = DataSourceUtils.getConnection(dataSource); + try { + connection.setAutoCommit(false); + final Object result = method.invoke(target, args); + connection.commit(); + + return result; + } catch (RuntimeException | SQLException e) { + throw handleTransactionFailure(connection, e); + } finally { + DataSourceUtils.releaseConnection(connection, dataSource); + } + } + + private RuntimeException handleTransactionFailure(final Connection connection, final Exception e) { + try { + connection.rollback(); + return new RuntimeException(e); + } catch (SQLException ex) { + return new SQLTransactionRollbackException(ex); + } + } +} diff --git a/app/src/main/java/com/techcourse/service/UserService.java b/app/src/main/java/com/techcourse/service/UserService.java index 61a9f5c26a..48e1c24e86 100644 --- a/app/src/main/java/com/techcourse/service/UserService.java +++ b/app/src/main/java/com/techcourse/service/UserService.java @@ -1,65 +1,11 @@ package com.techcourse.service; -import com.techcourse.config.DataSourceConfig; -import com.techcourse.dao.UserDaoWithJdbcTemplate; -import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; -import com.techcourse.domain.UserHistory; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Optional; -import javax.sql.DataSource; -import org.springframework.dao.SQLTransactionRollbackException; -import org.springframework.jdbc.datasource.DataSourceUtils; -public class UserService { +public interface UserService { + User findById(final long id); - private final UserDaoWithJdbcTemplate userDao; - private final UserHistoryDao userHistoryDao; - private final DataSource dataSource; + void insert(final User user); - public UserService(final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) { - this.dataSource = DataSourceConfig.getInstance(); - this.userDao = userDao; - this.userHistoryDao = userHistoryDao; - } - - public User findById(final long id) { - final Optional user = userDao.findById(id); - if (user.isEmpty()) { - throw new IllegalArgumentException("회원을 찾을 수 없음"); - } - return user.get(); - } - - public void insert(final User user) { - userDao.insert(user); - } - - public void changePassword(final long id, final String newPassword, final String createBy) { - final 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 (RuntimeException | SQLException e) { - handleTransactionFailure(connection, e); - } finally { - DataSourceUtils.releaseConnection(connection, dataSource); - } - } - - private void handleTransactionFailure(final Connection connection, final Exception e) { - try { - connection.rollback(); - throw new RuntimeException(e); - } catch (SQLException ex) { - throw new SQLTransactionRollbackException(ex); - } - } + void changePassword(final long id, final String newPassword, final String createBy); } diff --git a/app/src/main/java/com/techcourse/service/UserServiceImpl.java b/app/src/main/java/com/techcourse/service/UserServiceImpl.java new file mode 100644 index 0000000000..f5e42f3e05 --- /dev/null +++ b/app/src/main/java/com/techcourse/service/UserServiceImpl.java @@ -0,0 +1,40 @@ +package com.techcourse.service; + +import com.techcourse.dao.UserDaoWithJdbcTemplate; +import com.techcourse.dao.UserHistoryDao; +import com.techcourse.domain.User; +import com.techcourse.domain.UserHistory; +import java.util.Optional; + +public class UserServiceImpl implements UserService { + + private final UserDaoWithJdbcTemplate userDao; + private final UserHistoryDao userHistoryDao; + + public UserServiceImpl(final UserDaoWithJdbcTemplate userDao, final UserHistoryDao userHistoryDao) { + this.userDao = userDao; + this.userHistoryDao = userHistoryDao; + } + + @Override + public User findById(final long id) { + final Optional user = userDao.findById(id); + if (user.isEmpty()) { + throw new IllegalArgumentException("회원을 찾을 수 없음"); + } + return user.get(); + } + + @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/test/java/com/techcourse/service/UserServiceTest.java b/app/src/test/java/com/techcourse/service/UserServiceTest.java index 8ee3c3d3b3..90dd65ffaa 100644 --- a/app/src/test/java/com/techcourse/service/UserServiceTest.java +++ b/app/src/test/java/com/techcourse/service/UserServiceTest.java @@ -8,6 +8,7 @@ import com.techcourse.dao.UserHistoryDao; import com.techcourse.domain.User; import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; +import java.lang.reflect.Proxy; import javax.sql.DataSource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -30,7 +31,7 @@ void setUp() { @Test void testChangePassword() { final var userHistoryDao = new UserHistoryDao(dataSource); - final var userService = new UserService(userDao, userHistoryDao); + final UserService userService = getTransactionalUserService(userHistoryDao); final var newPassword = "qqqqq"; final var createBy = "gugu"; @@ -46,7 +47,7 @@ void testChangePassword() { void testTransactionRollback() { // 트랜잭션 롤백 테스트를 위해 mock으로 교체 final var userHistoryDao = new MockUserHistoryDao(dataSource); - final var userService = new UserService(userDao, userHistoryDao); + final UserService userService = getTransactionalUserService(userHistoryDao); final var newPassword = "newPassword"; final var createBy = "gugu"; @@ -58,4 +59,10 @@ void testTransactionRollback() { assertThat(actual.getPassword()).isNotEqualTo(newPassword); } + + private UserService getTransactionalUserService(final UserHistoryDao userHistoryDao) { + return (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), + new Class[]{UserService.class}, + new TransactionProxyHandler(new UserServiceImpl(userDao, userHistoryDao), dataSource)); + } } From 4a0ba70cce8e4164f7a144012c842a44428388cc Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Thu, 12 Oct 2023 10:34:11 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=204=EB=8B=A8=EA=B3=84=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20-=20TransactionProxyHandler=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=8D=98=EC=A7=80=EB=8A=94=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EB=A1=9C=20RuntimeException=20=EB=8C=80=EC=8B=A0=20Exception?= =?UTF-8?q?=20=EB=8D=98=EC=A7=80=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/techcourse/service/TransactionProxyHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java b/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java index 58a15be435..1efaf9d84b 100644 --- a/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java +++ b/app/src/main/java/com/techcourse/service/TransactionProxyHandler.java @@ -34,10 +34,10 @@ public Object invoke(final Object proxy, final Method method, final Object[] arg } } - private RuntimeException handleTransactionFailure(final Connection connection, final Exception e) { + private Exception handleTransactionFailure(final Connection connection, final Exception e) { try { connection.rollback(); - return new RuntimeException(e); + return e; } catch (SQLException ex) { return new SQLTransactionRollbackException(ex); } From 5e0c2ed9c28e0592767fe57ab4cec8678c3a4d88 Mon Sep 17 00:00:00 2001 From: BackFoxx Date: Thu, 12 Oct 2023 11:06:23 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=204=EB=8B=A8=EA=B3=84=20=ED=94=BC?= =?UTF-8?q?=EB=93=9C=EB=B0=B1=20-=20transaction=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=EC=9D=80=20=EC=8B=A4=ED=96=89=20=ED=9B=84=20Connectio?= =?UTF-8?q?n=20=EC=97=B0=EA=B2=B0=EC=9D=84=20=EB=81=8A=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jdbc/core/JdbcTemplate.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) 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 9bd5e5180b..aa12d4b3fd 100644 --- a/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -12,6 +12,7 @@ import javax.sql.DataSource; import org.springframework.dao.SQLExceptionTranslator; +import org.springframework.dao.SQLNonTransientConnectionException; import org.springframework.jdbc.datasource.DataSourceUtils; public class JdbcTemplate { @@ -35,6 +36,8 @@ public int update(String sql, Object... parameters) { } catch (SQLException e) { log.error(e.getMessage(), e); throw SQLExceptionTranslator.translate(e); + } finally { + releaseIfNotTransacting(connection); } } @@ -58,16 +61,8 @@ public Optional queryForObject(String sql, RowMapper rowMapper, Object } catch (SQLException e) { log.error(e.getMessage(), e); throw SQLExceptionTranslator.translate(e); - } - } - - private static void verifyResultRowSize(final ResultSet rs, final int rowSize) throws SQLException { - rs.last(); - if (rowSize < rs.getRow()) { - throw new SQLException(String.format("결과가 1개인 줄 알았는데, %d개 나왔서!", rs.getRow())); - /** - * 예외 원문 : Incorrect result size: expected 1, actual n - */ + } finally { + releaseIfNotTransacting(connection); } } @@ -89,6 +84,18 @@ public List query(String sql, RowMapper rowMapper, Object... parameter } catch (SQLException e) { log.error(e.getMessage(), e); throw SQLExceptionTranslator.translate(e); + } finally { + releaseIfNotTransacting(connection); + } + } + + private static void verifyResultRowSize(final ResultSet rs, final int rowSize) throws SQLException { + rs.last(); + if (rowSize < rs.getRow()) { + throw new SQLException(String.format("결과가 1개인 줄 알았는데, %d개 나왔서!", rs.getRow())); + /** + * 예외 원문 : Incorrect result size: expected 1, actual n + */ } } @@ -98,4 +105,14 @@ private static void setQueryParameters(final PreparedStatement pstmt, final Obje pstmt.setObject(i, parameters[i - 1]); } } + + private void releaseIfNotTransacting(final Connection connection) { + try { + if (connection.getAutoCommit()) { + DataSourceUtils.releaseConnection(connection, dataSource); + } + } catch (SQLException e) { + throw new SQLNonTransientConnectionException(e); + } + } }