Skip to content

Commit

Permalink
jdbc step4 주드 미션 제출합니다 (#552)
Browse files Browse the repository at this point in the history
* 패키지 위치 변경 및 코드 정리

* feat: 트랜잭션 required 형태 전파

* refactor: exception 처리 수정

---------

Co-authored-by: kang-hyungu <hkkang@woowahan.com>
  • Loading branch information
kevstevie and kang-hyungu authored Oct 13, 2023
1 parent 7e8c6d3 commit 393ace4
Show file tree
Hide file tree
Showing 21 changed files with 313 additions and 149 deletions.
25 changes: 12 additions & 13 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.exception.ResultSetMappingException;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

Expand All @@ -29,39 +28,39 @@ public UserDao(final JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

public void insert(final Connection conn, final User user) {
public void insert(final User user) {
final String sql = "insert into users (account, password, email) values (?, ?, ?)";

jdbcTemplate.update(conn, sql, user.getAccount(), user.getPassword(), user.getEmail());
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail());
}

public void update(final Connection conn, final User user) {
public void update(final User user) {
final var sql = "update users set account = ?, email = ?, password = ? where id = ?";

jdbcTemplate.update(conn, sql, user.getAccount(), user.getEmail(), user.getPassword(), user.getId());
jdbcTemplate.update(sql, user.getAccount(), user.getEmail(), user.getPassword(), user.getId());
}

public List<User> findAll(final Connection conn) {
public List<User> findAll() {
final String sql = "select * from users";

return jdbcTemplate.query(conn, sql, ROW_MAPPER);
return jdbcTemplate.query(sql, ROW_MAPPER);
}

public User findById(final Connection conn, final Long id) {
public User findById(final Long id) {
final var sql = "select id, account, password, email from users where id = ?";

return jdbcTemplate.queryForObject(conn, sql, ROW_MAPPER, id);
return jdbcTemplate.queryForObject(sql, ROW_MAPPER, id);
}

public User findByAccount(final Connection conn, final String account) {
public User findByAccount(final String account) {
final var sql = "select id, account, password, email from users where account = ?";

return jdbcTemplate.queryForObject(conn, sql, ROW_MAPPER, account);
return jdbcTemplate.queryForObject(sql, ROW_MAPPER, account);
}

public void deleteAll(final Connection conn) {
public void deleteAll() {
final var sql = "delete from users";

jdbcTemplate.update(conn, sql);
jdbcTemplate.update(sql);
}
}
5 changes: 1 addition & 4 deletions app/src/main/java/com/techcourse/dao/UserHistoryDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.Connection;

public class UserHistoryDao {

private static final Logger log = LoggerFactory.getLogger(UserHistoryDao.class);
Expand All @@ -17,11 +15,10 @@ 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, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)";

jdbcTemplate.update(
conn,
sql,
userHistory.getUserId(),
userHistory.getAccount(),
Expand Down
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(UserDao userDao, 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));
}
}
30 changes: 30 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,30 @@
package com.techcourse.service;

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

public class TxUserService implements UserService {

private final UserService userService;
private final TransactionTemplate transactionTemplate;

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

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

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

@Override
public void changePassword(final long id, final String newPassword, final String createBy) {
transactionTemplate.execute(() -> userService.changePassword(id, newPassword, createBy));
}
}
77 changes: 4 additions & 73 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,81 +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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.SQLException;
public interface UserService {

public class UserService {
User findById(final long id);

private static final Logger log = LoggerFactory.getLogger(UserService.class);
void insert(final User user);

private final UserDao userDao;
private final UserHistoryDao userHistoryDao;
private final DataSource dataSource = DataSourceConfig.getInstance();

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

public User findById(final long id) {
try (final var conn = dataSource.getConnection()) {
try {
conn.setAutoCommit(false);

return userDao.findById(conn, id);
} catch (Exception e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
}
conn.commit();
} catch (SQLException e) {
log.info(e.getMessage());
}
throw new RuntimeException();
}

public void insert(final User user) {
try (final var conn = dataSource.getConnection()) {
try {
conn.setAutoCommit(false);

userDao.insert(conn, user);
} catch (Exception e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
}
conn.commit();
} catch (SQLException e) {
log.info(e.getMessage());
}
}

public void changePassword(final long id, final String newPassword, final String createBy) {
try (final var conn = dataSource.getConnection()) {
try {
conn.setAutoCommit(false);

final var user = findById(id);
user.changePassword(newPassword);
userDao.update(conn, user);
userHistoryDao.log(conn, new UserHistory(user, createBy));
} catch (Exception e) {
conn.rollback();
} finally {
conn.setAutoCommit(true);
}
conn.commit();
} catch (SQLException e) {
log.info(e.getMessage());
}
}
void changePassword(final long id, final String newPassword, final String createBy);
}
26 changes: 13 additions & 13 deletions app/src/test/java/com/techcourse/dao/UserDaoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,27 @@ void setup() {

userDao = new UserDao(new JdbcTemplate(DataSourceConfig.getInstance()));
final var user = new User("gugu", "password", "hkkang@woowahan.com");
userDao.insert(conn, user);
userDao.insert(user);
}

@Test
void findAll() {
final var users = userDao.findAll(conn);
final var users = userDao.findAll();

assertThat(users).isNotEmpty();
}

@Test
void findById() {
final var user = userDao.findById(conn, 1L);
final var user = userDao.findById(1L);

assertThat(user.getAccount()).isEqualTo("gugu");
}

@Test
void findByAccount() {
final var account = "gugu";
final var user = userDao.findByAccount(conn, account);
final var user = userDao.findByAccount(account);

assertThat(user.getAccount()).isEqualTo(account);
}
Expand All @@ -64,39 +64,39 @@ void findByAccount() {
void insert() {
final var account = "insert-gugu";
final var user = new User(account, "password", "hkkang@woowahan.com");
userDao.insert(conn, user);
userDao.insert(user);

final var actual = userDao.findById(conn, 2L);
final var actual = userDao.findById(2L);

assertThat(actual.getAccount()).isEqualTo(account);
}

@Test
void update() {
final var newPassword = "password99";
final var user = userDao.findById(conn, 1L);
final var user = userDao.findById(1L);
user.changePassword(newPassword);

userDao.update(conn, user);
userDao.update(user);

final var actual = userDao.findById(conn, 1L);
final var actual = userDao.findById(1L);

assertThat(actual.getPassword()).isEqualTo(newPassword);
}

@Test
void deleteAll() {
userDao.deleteAll(conn);
userDao.deleteAll();

List<User> users = userDao.findAll(conn);
List<User> users = userDao.findAll();
assertThat(users).isEmpty();
}

@Test
void findObjectReturnNull() {
userDao.deleteAll(conn);
userDao.deleteAll();

assertThatThrownBy(() -> userDao.findById(conn, 1L))
assertThatThrownBy(() -> userDao.findById(1L))
.isInstanceOf(DataAccessException.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.Connection;

public class MockUserHistoryDao extends UserHistoryDao {

public MockUserHistoryDao(final JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}

@Override
public void log(Connection conn, final UserHistory userHistory) {
public void log(final UserHistory userHistory) {
throw new DataAccessException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,35 @@
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

import java.sql.SQLException;
import org.springframework.transaction.support.TransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

class UserServiceTest {
class TxUserServiceTest {

private JdbcTemplate jdbcTemplate;
private UserDao userDao;

@BeforeEach
void setUp() throws SQLException {
void setUp() {
this.jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance());
this.userDao = new UserDao(jdbcTemplate);

DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());
final var user = new User("gugu", "password", "hkkang@woowahan.com");
userDao.insert(DataSourceConfig.getInstance().getConnection(), user);
userDao.insert(user);
}

@Test
void testChangePassword() {
final var transactionTemplate = new TransactionTemplate(new TransactionManager(DataSourceConfig.getInstance()));
final var userHistoryDao = new UserHistoryDao(jdbcTemplate);
final var userService = new UserService(userDao, userHistoryDao);
final var appUserService = new AppUserService(userDao, userHistoryDao);
final var userService = new TxUserService(appUserService, transactionTemplate);

final var newPassword = "qqqqq";
final var createBy = "gugu";
Expand All @@ -43,15 +47,19 @@ void testChangePassword() {
}

@Test
void testTransactionRollback() {
void testTransactionRollback2() {
// 트랜잭션 롤백 테스트를 위해 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(new TransactionManager(DataSourceConfig.getInstance())));

final var newPassword = "newPassword";
final var createBy = "gugu";
// 트랜잭션이 정상 동작하는지 확인하기 위해 의도적으로 MockUserHistoryDao에서 예외를 발생시킨다.
userService.changePassword(1L, newPassword, createBy);
assertThrows(DataAccessException.class,
() -> userService.changePassword(1L, newPassword, createBy));

final var actual = userService.findById(1L);

Expand Down
Loading

0 comments on commit 393ace4

Please sign in to comment.