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단계] 베베(최원용) 미션 제출합니다. #590

Merged
merged 5 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions app/src/main/java/com/techcourse/dao/JdbcUserHistoryDao.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package com.techcourse.dao;

import com.techcourse.domain.UserHistory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JdbcUserHistoryDao implements UserHistoryDao {

private final JdbcTemplate jdbcTemplate;
Expand Down
1 change: 0 additions & 1 deletion app/src/main/java/com/techcourse/domain/UserHistory.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.techcourse.domain;

import java.sql.Connection;
import java.time.LocalDateTime;

public class UserHistory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.techcourse.dao.UserDao;
import com.techcourse.domain.User;

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

public class UserRepository {
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.JdbcUserHistoryDao;
import com.techcourse.dao.UserDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import com.techcourse.repository.UserRepository;

public class AppUserService implements UserService {

private final UserRepository userRepository;
private final JdbcUserHistoryDao jdbcUserHistoryDao;

public AppUserService(final UserDao userDao, final JdbcUserHistoryDao jdbcUserHistoryDao) {
this.userRepository = new UserRepository(userDao);
this.jdbcUserHistoryDao = jdbcUserHistoryDao;
}

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

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

@Override
public void changePassword(final long id, final String newPassword, final String createBy) {
final var user = findById(id);
user.changePassword(newPassword);
userRepository.update(user);
jdbcUserHistoryDao.log(new UserHistory(user, createBy));
}

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

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

import static com.techcourse.config.DataSourceConfig.getInstance;

public class TxUserService implements UserService {

private final UserService userService;
private final TransactionManager transactionManager;

public TxUserService(UserService userService) {
this.userService = userService;
this.transactionManager = new TransactionManager(getInstance());
}

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

@Override
public void insert(final User user) {
transactionManager.execute(connection -> {
userService.insert(user);
return null;
}
);
}
wonyongChoi05 marked this conversation as resolved.
Show resolved Hide resolved

@Override
public void changePassword(long id, String newPassword, String createBy) {
transactionManager.execute(connection -> {
userService.changePassword(id, newPassword, createBy);
return null;
});
}
wonyongChoi05 marked this conversation as resolved.
Show resolved Hide resolved

}
40 changes: 5 additions & 35 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
package com.techcourse.service;

import com.techcourse.dao.UserDao;
import com.techcourse.dao.JdbcUserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import com.techcourse.repository.UserRepository;
import org.springframework.jdbc.transaction.TransactionManager;

import javax.sql.DataSource;
public interface UserService {

public class UserService {
User findById(final long id);
void insert(final User user);
void changePassword(final long id, final String newPassword, final String createBy);

private final TransactionManager transactionManager;
private final UserRepository userRepository;
private final JdbcUserHistoryDao jdbcUserHistoryDao;

public UserService(final DataSource dataSource, final UserDao userDao, final JdbcUserHistoryDao jdbcUserHistoryDao) {
this.transactionManager = new TransactionManager(dataSource);
this.userRepository = new UserRepository(userDao);
this.jdbcUserHistoryDao = jdbcUserHistoryDao;
}

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

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

public void changePassword(final long id, final String newPassword, final String createBy) {
transactionManager.execute(connection -> {
final var user = findById(id);
user.changePassword(newPassword);
userRepository.update(user);
jdbcUserHistoryDao.log(new UserHistory(user, createBy));
return null;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

class UserServiceTest {
class AppUserServiceTest {

private JdbcTemplate jdbcTemplate;
private UserDao userDao;
Expand All @@ -32,7 +32,7 @@ void setUp() {
@Test
void testChangePassword() {
final var userHistoryDao = new JdbcUserHistoryDao(jdbcTemplate);
final var userService = new UserService(DataSourceConfig.getInstance(), userDao, userHistoryDao);
final var userService = new AppUserService(userDao, userHistoryDao);

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

final var newPassword = "newPassword";
final var createBy = "gugu";
Expand All @@ -59,4 +62,5 @@ void testTransactionRollback() {

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

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.springframework.jdbc.core;

import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.transaction.TransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.sql.Connection;
Expand All @@ -11,13 +13,15 @@
import java.util.Optional;

import static java.util.Collections.singletonList;
import static org.springframework.jdbc.datasource.DataSourceUtils.*;
import static org.springframework.transaction.support.TransactionSynchronizationManager.*;

public class JdbcTemplate {

private final TransactionManager transactionManager;
private final DataSource dataSource;

public JdbcTemplate(final DataSource dataSource) {
this.transactionManager = new TransactionManager(dataSource);
this.dataSource = dataSource;
}

public int update(final String sql, final Object... conditions) {
Expand All @@ -43,7 +47,7 @@ private <T> T getRowByQuery(final PreparedStatement preparedStatement, final Row
}

private <T> T getResult(final PreparedStatementExecutor<T> executor, final String sql, final Object... conditions) {
Connection connection = transactionManager.getConnection();
Connection connection = getConnection(dataSource);
try (
PreparedStatement preparedStatement = connection.prepareStatement(sql);
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.sql.Connection;
import java.sql.SQLException;

// 4단계 미션에서 사용할 것
public abstract class DataSourceUtils {

private DataSourceUtils() {}
Expand All @@ -30,6 +29,7 @@ public static Connection getConnection(DataSource dataSource) throws CannotGetJd
public static void releaseConnection(Connection connection, DataSource dataSource) {
try {
connection.close();
TransactionSynchronizationManager.unbindResource(dataSource);
wonyongChoi05 marked this conversation as resolved.
Show resolved Hide resolved
} catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Failed to close JDBC Connection");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package org.springframework.jdbc.transaction;

import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class TransactionManager {
import static org.springframework.jdbc.datasource.DataSourceUtils.*;
import static org.springframework.jdbc.datasource.DataSourceUtils.releaseConnection;
import static org.springframework.transaction.support.TransactionSynchronizationManager.*;
wonyongChoi05 marked this conversation as resolved.
Show resolved Hide resolved

private static final ThreadLocal<Connection> connectionInThread = new ThreadLocal<>();
public class TransactionManager {

private final DataSource dataSource;

Expand All @@ -27,54 +32,33 @@ public <T> T execute(final TransactionExecutor<T> transactionExecutor) {
}

public Connection begin() {
Connection connection = getConnection();
Connection connection = getConnection(dataSource);
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException(e);
}
connectionInThread.set(connection);
return connection;
}

public void commit() {
Connection connection = getConnection();
Connection connection = getConnection(dataSource);
try {
connection.commit();
} catch (SQLException e) {
throw new RuntimeException(e);
}
init(connection);
releaseConnection(connection, dataSource);
}

public void rollback() {
Connection connection = getConnection();
Connection connection = getConnection(dataSource);
try {
connection.rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
init(connection);
}

private void init(final Connection connection) {
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
connectionInThread.remove();
}

public Connection getConnection() {
if (connectionInThread.get() == null) {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
return connectionInThread.get();
releaseConnection(connection, dataSource);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

public abstract class TransactionSynchronizationManager {
Expand All @@ -11,13 +12,25 @@ public abstract class TransactionSynchronizationManager {
private TransactionSynchronizationManager() {}

public static Connection getResource(DataSource key) {
return null;
final Map<DataSource, Connection> resource = resources.get();
if (resource == null) {
return null;
}
return resource.get(key);
}

public static void bindResource(DataSource key, Connection value) {
Map<DataSource, Connection> resource = resources.get();
if (resource == null) {
resource = new HashMap<>();
resources.set(resource);
}
resource.put(key, value);
Comment on lines +23 to +28

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도한 대로 동작하는지 확인하기 위해 테스트가 필요하지 않을까요?

}

public static Connection unbindResource(DataSource key) {
return null;
final Map<DataSource, Connection> resource = resources.get();
return resource.remove(key);
}

}
Loading