Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JDBC 라이브러리 구현하기 - 4단계] 쥬니(전정준) 미션 제출합니다. #516

Merged
merged 9 commits into from
Oct 10, 2023
9 changes: 4 additions & 5 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -30,20 +29,20 @@ public UserDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

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

log.debug("query : {}", sql);

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

public void update(Connection connection, User user) {
public void update(User user) {
String sql = "UPDATE users SET account = ?, password = ?, email = ? WHERE id = ?";

log.debug("query : {}", sql);

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<User> findAll() {
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/java/com/techcourse/dao/UserHistoryDao.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.techcourse.dao;

import com.techcourse.domain.UserHistory;
import java.sql.Connection;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

Expand All @@ -17,10 +16,10 @@ public UserHistoryDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

public void log(Connection connection, UserHistory userHistory) {
public void log(UserHistory userHistory) {
String sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)";

jdbcTemplate.update(connection, sql, userHistory.getUserId(), userHistory.getAccount(),
jdbcTemplate.update(sql, userHistory.getUserId(), userHistory.getAccount(),
userHistory.getPassword(), userHistory.getEmail(), userHistory.getCreatedAt(),
userHistory.getCreateBy());
}
Expand Down
37 changes: 37 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,37 @@
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) {
User user = findById(id);
user.changePassword(newPassword);

userDao.update(user);
userHistoryDao.log(new UserHistory(user, createBy));
}

}
36 changes: 36 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,36 @@
package com.techcourse.service;

import com.techcourse.domain.User;
import org.springframework.transaction.TransactionManager;

public class TxUserService implements UserService {

private final TransactionManager transactionManager;
private final UserService appUserService;

public TxUserService(TransactionManager transactionManager, UserService appUserService) {
this.transactionManager = transactionManager;
this.appUserService = appUserService;
}

@Override
public User findById(long id) {
return transactionManager.execute(() -> appUserService.findById(id), true);
}

@Override
public void insert(User user) {
transactionManager.execute(() -> {
appUserService.insert(user);
return null;
}, false);
}

@Override
public void changePassword(long id, String newPassword, String createBy) {
transactionManager.execute(() -> {
appUserService.changePassword(id, newPassword, createBy);
return null;
}, false);
}
}
54 changes: 4 additions & 50 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,13 @@
package com.techcourse.service;

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 org.springframework.dao.DataAccessException;
import org.springframework.transaction.Transaction;
import org.springframework.transaction.TransactionManager;

public class UserService {
public interface UserService {

private final TransactionManager transactionManager;
private final UserDao userDao;
private final UserHistoryDao userHistoryDao;
User findById(long id);

public UserService(TransactionManager transactionManager, UserDao userDao, UserHistoryDao userHistoryDao) {
this.transactionManager = transactionManager;
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}
void insert(User user);

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

public void insert(User user) {
Transaction transaction = transactionManager.getTransaction();
transaction.start();

try {
userDao.insert(transaction.getConnection(), user);
transaction.commit();
} catch (DataAccessException e) {
transaction.rollback();
throw e;
}
}

public void changePassword(long id, String newPassword, String createBy) {
Transaction transaction = transactionManager.getTransaction();
transaction.start();
try {
Connection connection = transaction.getConnection();
User user = findById(id);

user.changePassword(newPassword);
userDao.update(connection, user);
userHistoryDao.log(connection, new UserHistory(user, createBy));

transaction.commit();
} catch (DataAccessException e) {
transaction.rollback();
throw e;
}
}
void changePassword(long id, String newPassword, String createBy);

}
16 changes: 7 additions & 9 deletions app/src/test/java/com/techcourse/dao/UserDaoTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,16 @@ class UserDaoTest {

private final JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance());
private UserDao userDao;
private DataSource dataSource;

@BeforeEach
void setup() throws SQLException {
dataSource = DataSourceConfig.getInstance();
DatabasePopulatorUtils.execute(dataSource);
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());

jdbcTemplate.update(dataSource.getConnection(), "TRUNCATE TABLE users RESTART IDENTITY");
jdbcTemplate.update("TRUNCATE TABLE users RESTART IDENTITY");
userDao = new UserDao(DataSourceConfig.getInstance());

User user = new User("gugu", "password", "[email protected]");
userDao.insert(dataSource.getConnection(), user);
userDao.insert(user);
}

@Test
Expand All @@ -42,7 +40,7 @@ void findAll() {

@Test
void findById() throws SQLException {
userDao.insert(dataSource.getConnection(), new User("gugu", "password", "[email protected]"));
userDao.insert(new User("gugu", "password", "[email protected]"));
User user = userDao.findById(1L);

assertThat(user.getAccount()).isEqualTo("gugu");
Expand All @@ -60,7 +58,7 @@ void findByAccount() {
void insert() throws SQLException {
String account = "insert-gugu";
User user = new User(account, "password", "[email protected]");
userDao.insert(dataSource.getConnection(), user);
userDao.insert(user);

User actual = userDao.findById(2L);

Expand All @@ -73,7 +71,7 @@ void update() throws SQLException {
User user = userDao.findById(1L);
user.changePassword(newPassword);

userDao.update(dataSource.getConnection(), user);
userDao.update(user);

User actual = userDao.findById(1L);

Expand All @@ -88,7 +86,7 @@ void findByAccount_FailByMultipleResults() throws SQLException {
assertThat(findUser).isNotNull();

User duplicateUser = new User("gugu", "password", "[email protected]");
userDao.insert(dataSource.getConnection(), duplicateUser);
userDao.insert(duplicateUser);

//when then
assertThatThrownBy(() -> userDao.findByAccount("gugu"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,35 @@
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
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;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.TransactionManager;

class UserServiceTest {
class AppUserServiceTest {

private JdbcTemplate jdbcTemplate;
private UserDao userDao;
private TransactionManager transactionManager;

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

DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());
DatabasePopulatorUtils.execute(dataSource);
final var user = new User("gugu", "password", "[email protected]");
userDao.insert(dataSource.getConnection(), user);
userDao.insert(user);
}

@Test
void testChangePassword() {
final var userHistoryDao = new UserHistoryDao(jdbcTemplate);
final var userService = new UserService(transactionManager, userDao, userHistoryDao);
final var userService = new AppUserService(userDao, userHistoryDao);

final var newPassword = "qqqqq";
final var createBy = "gugu";
Expand All @@ -52,7 +51,10 @@ void testChangePassword() {
void testTransactionRollback() {
// 트랜잭션 롤백 테스트를 위해 mock으로 교체
final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate);
final var userService = new UserService(transactionManager, userDao, userHistoryDao);
// 애플리케이션 서비스
final var appUserService = new AppUserService(userDao, userHistoryDao);
// 트랜잭션 서비스 추상화
final var userService = new TxUserService(transactionManager, appUserService);

final var newPassword = "newPassword";
final var createBy = "gugu";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public MockUserHistoryDao(final JdbcTemplate jdbcTemplate) {
}

@Override
public void log(Connection connection, final UserHistory userHistory) {
public void log(final UserHistory userHistory) {
throw new DataAccessException();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.springframework.jdbc.core;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
Expand All @@ -17,8 +16,8 @@ public JdbcTemplate(DataSource dataSource) {
this.queryTemplate = new QueryTemplate(dataSource);
}

public void update(Connection connection, String sql, Object... args) {
queryTemplate.update(connection, sql, PreparedStatement::executeUpdate, args);
public void update(String sql, Object... args) {
queryTemplate.update(sql, PreparedStatement::executeUpdate, args);
}

public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceUtils;

public class QueryTemplate {

Expand All @@ -19,12 +20,15 @@ public QueryTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}

public <T> T update(Connection connection, String sql, UpdateExecutor<T> executor, Object... args) {
public <T> T update(String sql, UpdateExecutor<T> executor, Object... args) {
Connection connection = DataSourceUtils.getConnection(dataSource);
try (PreparedStatement preparedStatement = getInitializedPreparedStatement(sql, connection, args)) {
return executor.execute(preparedStatement);
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(e);
} finally {
DataSourceUtils.closeConnectionIfNotInTransaction(dataSource, connection);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
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);
Expand All @@ -28,6 +28,19 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd
}

public static void releaseConnection(Connection connection, DataSource dataSource) {
try {
TransactionSynchronizationManager.unbindResource(dataSource);
connection.close();
} catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection");
}
}

public static void closeConnectionIfNotInTransaction(DataSource dataSource, Connection connection) {
if (TransactionSynchronizationManager.isInTransaction(dataSource)) {
return;
}

try {
connection.close();
} catch (SQLException ex) {
Expand Down
Loading
Loading