Skip to content

Commit

Permalink
feat: userService 에서 커넥션 관리를 하지 않도록 TransactionTemplate을 만들음
Browse files Browse the repository at this point in the history
  • Loading branch information
jyeost committed Oct 11, 2023
1 parent 7ff7f19 commit 3990184
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 51 deletions.
35 changes: 35 additions & 0 deletions app/src/main/java/com/techcourse/service/AppUserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.techcourse.service;

import com.techcourse.dao.UserDao;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;

public class AppUserService implements UserService {

private final UserDao userDao;
private final UserHistoryDao userHistoryDao;

public AppUserService(final UserDao userDao, final UserHistoryDao userHistoryDao) {
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}

@Override
public User findById(final long id) {
return userDao.findById(id);
}

@Override
public void insert(final User user) {
userDao.insert(user);
}

@Override
public void changePassword(final long id, final String newPassword, final String createBy) {
final var findUser = findById(id);
findUser.changePassword(newPassword);
userDao.update(findUser);
userHistoryDao.log(new UserHistory(findUser, createBy));
}
}
37 changes: 37 additions & 0 deletions app/src/main/java/com/techcourse/service/TxUserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.techcourse.service;

import com.techcourse.domain.User;
import org.springframework.transaction.support.TransactionTemplate;

public class TxUserService implements UserService {

private final AppUserService userService;

private final TransactionTemplate transactionTemplate;

public TxUserService(final AppUserService userService, final TransactionTemplate transactionTemplate) {
this.userService = userService;
this.transactionTemplate = transactionTemplate;
}

@Override
public User findById(final long id) {
return userService.findById(id);
}

@Override
public void insert(final User user) {
transactionTemplate.execute(() -> {
userService.insert(user);
return null;
});
}

@Override
public void changePassword(final long id, final String newPassword, final String createBy) {
transactionTemplate.execute(() -> {
userService.changePassword(id, newPassword, createBy);
return null;
});
}
}
53 changes: 4 additions & 49 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,56 +1,11 @@
package com.techcourse.service;

import com.techcourse.config.DataSourceConfig;
import com.techcourse.dao.UserDao;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.sql.SQLException;
public interface UserService {
User findById(final long id);

public class UserService {
void insert(final User user);

private final UserDao userDao;
private final UserHistoryDao userHistoryDao;

public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao) {
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}

public User findById(final long id) {
return userDao.findById(id);
}

public void insert(final User user) {
userDao.insert(user);
}

public void changePassword(final long id, final String newPassword, final String createBy) {
final var findUser = findById(id);

final DataSource dataSource = DataSourceConfig.getInstance();
final var connection = DataSourceUtils.getConnection(dataSource);
try {
connection.setAutoCommit(false);
findUser.changePassword(newPassword);
userDao.update(findUser);
userHistoryDao.log(new UserHistory(findUser, createBy));
connection.commit();
} catch (SQLException e) {
try {
connection.rollback();
} catch (SQLException ex) {
throw new DataAccessException(ex);
}
throw new DataAccessException(e);
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
TransactionSynchronizationManager.unbindResource(dataSource);
}
}
void changePassword(final long id, final String newPassword, final String createBy);
}
8 changes: 6 additions & 2 deletions app/src/test/java/com/techcourse/service/UserServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.support.TransactionTemplate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand All @@ -31,7 +32,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";
Expand All @@ -46,7 +47,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, new TransactionTemplate(DataSourceConfig.getInstance()));

final var newPassword = "newPassword";
final var createBy = "gugu";
Expand Down
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();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
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(final DataSource dataSource) {
this.dataSource = dataSource;
}

public <T> T execute(final TransactionExecutor<T> transactionExecutor) {
final var connection = DataSourceUtils.getConnection(dataSource);
try {
connection.setAutoCommit(false);
final T result = transactionExecutor.execute();
commit(connection);
return result;
} catch (SQLException e) {
rollback(connection);
throw new DataAccessException(e);
} finally {
turnOnAutoCommit(connection);
DataSourceUtils.releaseConnection(connection, dataSource);
TransactionSynchronizationManager.unbindResource(dataSource);
}
}

private void commit(final Connection connection) {
try {
connection.commit();
} catch (SQLException e) {
throw new DataAccessException(e);
}
}

private void rollback(final Connection connection) {
try {
connection.rollback();
} catch (SQLException ex) {
throw new DataAccessException(ex);
}
}

private void turnOnAutoCommit(final Connection connection) {
try {
connection.commit();
} catch (SQLException e) {
throw new DataAccessException(e);
}
}
}

0 comments on commit 3990184

Please sign in to comment.