-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
100 additions
and
73 deletions.
There are no files selected for viewing
67 changes: 15 additions & 52 deletions
67
app/src/main/java/com/techcourse/service/TxUserService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,36 @@ | ||
package com.techcourse.service; | ||
|
||
import com.techcourse.config.DataSourceConfig; | ||
import com.techcourse.domain.User; | ||
import org.springframework.jdbc.datasource.DataSourceUtils; | ||
import org.springframework.transaction.support.TransactionSynchronizationManager; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
import java.sql.SQLTransactionRollbackException; | ||
import org.springframework.transaction.support.TransactionTemplate; | ||
|
||
public class TxUserService implements UserService { | ||
|
||
private UserService userService; | ||
private final DataSource dataSource = DataSourceConfig.getInstance(); | ||
private final TransactionTemplate transactionTemplate; | ||
private final UserService userService; | ||
|
||
public TxUserService(UserService userService) { | ||
public TxUserService(TransactionTemplate transactionTemplate, UserService userService) { | ||
this.transactionTemplate = transactionTemplate; | ||
this.userService = userService; | ||
} | ||
|
||
@Override | ||
public User findById(long id) throws SQLException { | ||
Connection connection = null; | ||
try { | ||
if (TransactionSynchronizationManager.hasConnection(dataSource)) { | ||
return userService.findById(id); | ||
} | ||
connection = DataSourceUtils.getConnection(dataSource); | ||
connection.setAutoCommit(false); | ||
User user = userService.findById(id); | ||
connection.commit(); | ||
DataSourceUtils.releaseConnection(connection, dataSource); | ||
return user; | ||
} catch (SQLException e) { | ||
connection.rollback(); | ||
throw new SQLTransactionRollbackException(e.getMessage()); | ||
} | ||
public User findById(long id) { | ||
return userService.findById(id); | ||
} | ||
|
||
@Override | ||
public void insert(User user) throws SQLException { | ||
Connection connection = null; | ||
try { | ||
if (TransactionSynchronizationManager.hasConnection(dataSource)) { | ||
userService.insert(user); | ||
return; | ||
} | ||
connection = DataSourceUtils.getConnection(dataSource); | ||
connection.setAutoCommit(false); | ||
public void insert(User user) { | ||
transactionTemplate.execute(() -> { | ||
userService.insert(user); | ||
connection.commit(); | ||
} catch (SQLException e) { | ||
connection.rollback(); | ||
throw new SQLTransactionRollbackException(e.getMessage()); | ||
} | ||
return null; | ||
}); | ||
} | ||
|
||
@Override | ||
public void changePassword(long id, String newPassword, String createBy) throws SQLException { | ||
Connection connection = DataSourceUtils.getConnection(dataSource); | ||
connection.setAutoCommit(false); | ||
try { | ||
public void changePassword(long id, String newPassword, String createBy) { | ||
transactionTemplate.execute(() -> { | ||
userService.changePassword(id, newPassword, createBy); | ||
connection.commit(); | ||
} catch (SQLException e) { | ||
connection.rollback(); | ||
throw new SQLTransactionRollbackException(e.getMessage()); | ||
} finally { | ||
DataSourceUtils.releaseConnection(connection, dataSource); | ||
} | ||
return null; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,7 @@ | |
import org.junit.jupiter.api.Test; | ||
import org.springframework.dao.DataAccessException; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.SQLException; | ||
import org.springframework.transaction.support.TransactionTemplate; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
|
@@ -20,23 +18,23 @@ class UserServiceTest { | |
|
||
private JdbcTemplate jdbcTemplate; | ||
private UserDao userDao; | ||
private DataSource dataSource; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
dataSource = DataSourceConfig.getInstance(); | ||
DatabasePopulatorUtils.execute(dataSource); | ||
this.jdbcTemplate = new JdbcTemplate(dataSource); | ||
this.jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance()); | ||
this.userDao = new UserDao(jdbcTemplate); | ||
|
||
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); | ||
var user = new User("gugu", "password", "[email protected]"); | ||
userDao.insert(user); | ||
} | ||
|
||
@Test | ||
void testChangePassword() throws SQLException { | ||
void testChangePassword() { | ||
var userHistoryDao = new UserHistoryDao(jdbcTemplate); | ||
var userService = new TxUserService(new AppUserService(userDao, userHistoryDao)); | ||
var transactionTemplate = new TransactionTemplate(DataSourceConfig.getInstance()); | ||
var appUserService = new AppUserService(userDao, userHistoryDao); | ||
var userService = new TxUserService(transactionTemplate, appUserService); | ||
|
||
var newPassword = "qqqqq"; | ||
var createBy = "gugu"; | ||
|
@@ -48,21 +46,22 @@ void testChangePassword() throws SQLException { | |
} | ||
|
||
@Test | ||
void testTransactionRollback() throws SQLException { | ||
void testTransactionRollback() { | ||
// 트랜잭션 롤백 테스트를 위해 mock으로 교체 | ||
final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate); | ||
var userHistoryDao = new MockUserHistoryDao(jdbcTemplate); | ||
var transactionTemplate = new TransactionTemplate(DataSourceConfig.getInstance()); | ||
// 애플리케이션 서비스 | ||
final var appUserService = new AppUserService(userDao, userHistoryDao); | ||
var appUserService = new AppUserService(userDao, userHistoryDao); | ||
// 트랜잭션 서비스 추상화 | ||
final var userService = new TxUserService(appUserService); | ||
var userService = new TxUserService(transactionTemplate, appUserService); | ||
|
||
final var newPassword = "newPassword"; | ||
final var createBy = "gugu"; | ||
var newPassword = "newPassword"; | ||
var createBy = "gugu"; | ||
// 트랜잭션이 정상 동작하는지 확인하기 위해 의도적으로 MockUserHistoryDao에서 예외를 발생시킨다. | ||
assertThrows(DataAccessException.class, | ||
() -> userService.changePassword(1L, newPassword, createBy)); | ||
|
||
final var actual = userService.findById(1L); | ||
var actual = userService.findById(1L); | ||
|
||
assertThat(actual.getPassword()).isNotEqualTo(newPassword); | ||
} | ||
|
7 changes: 7 additions & 0 deletions
7
jdbc/src/main/java/org/springframework/transaction/support/TransactionExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.springframework.transaction.support; | ||
|
||
@FunctionalInterface | ||
public interface TransactionExecutor<T> { | ||
|
||
T execute(); | ||
} |
60 changes: 60 additions & 0 deletions
60
jdbc/src/main/java/org/springframework/transaction/support/TransactionTemplate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.springframework.transaction.support; | ||
|
||
import org.springframework.dao.DataAccessException; | ||
import org.springframework.jdbc.datasource.DataSourceUtils; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.SQLException; | ||
|
||
public class TransactionTemplate { | ||
|
||
private final DataSource dataSource; | ||
|
||
public TransactionTemplate(DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public <T> T execute(TransactionExecutor<T> executor) { | ||
Connection connection = startTransaction(); | ||
try { | ||
T result = executor.execute(); | ||
commit(connection); | ||
return result; | ||
} catch (DataAccessException e) { | ||
rollback(connection); | ||
throw e; | ||
} finally { | ||
DataSourceUtils.releaseConnection(connection, dataSource); | ||
TransactionSynchronizationManager.unbindResource(dataSource); | ||
} | ||
} | ||
|
||
private Connection startTransaction() { | ||
Connection connection = DataSourceUtils.getConnection(dataSource); | ||
try { | ||
connection.setAutoCommit(false); | ||
} catch (SQLException e) { | ||
throw new DataAccessException(e.getMessage(), e); | ||
} | ||
return connection; | ||
} | ||
|
||
private void commit(Connection connection) { | ||
try { | ||
connection.commit(); | ||
connection.setAutoCommit(true); | ||
} catch (SQLException e) { | ||
throw new DataAccessException(e.getMessage(), e); | ||
} | ||
} | ||
|
||
private void rollback(Connection connection) { | ||
try { | ||
connection.rollback(); | ||
connection.setAutoCommit(true); | ||
} catch (SQLException e) { | ||
throw new DataAccessException(e.getMessage(), e); | ||
} | ||
} | ||
} |