Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class LoginController {

public LoginController() {
this.userService = new UserService(
DataSourceConfig.getInstance(),
new UserDao(DataSourceConfig.getInstance()),
new UserHistoryDao(DataSourceConfig.getInstance())
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class RegisterController {

public RegisterController() {
this.userService = new UserService(
DataSourceConfig.getInstance(),
new UserDao(DataSourceConfig.getInstance()),
new UserHistoryDao(DataSourceConfig.getInstance())
);
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.interface21.jdbc.core.JdbcTemplate;
import com.techcourse.domain.User;
import java.sql.Connection;
import java.util.List;
import javax.sql.DataSource;

Expand All @@ -27,6 +28,11 @@ public void update(final User user) {
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId());
}

public void update(final Connection connection, final User user) {
final var sql = "update users set account = ?, password = ?, email = ? where id = ?";
jdbcTemplate.update(connection, sql, user.getAccount(), user.getPassword(), user.getEmail(), user.getId());
}

public List<User> findAll() {
final var sql = "select id, account, password, email from users";

Expand Down
52 changes: 19 additions & 33 deletions app/src/main/java/com/techcourse/dao/UserHistoryDao.java
Original file line number Diff line number Diff line change
@@ -1,62 +1,48 @@
package com.techcourse.dao;

import com.techcourse.domain.UserHistory;
import com.interface21.jdbc.core.JdbcTemplate;
import com.techcourse.domain.UserHistory;
import java.sql.Connection;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public class UserHistoryDao {

private static final Logger log = LoggerFactory.getLogger(UserHistoryDao.class);

private final DataSource dataSource;
private final JdbcTemplate jdbcTemplate;

public UserHistoryDao(final DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public UserHistoryDao(final JdbcTemplate jdbcTemplate) {
this.dataSource = null;
this.jdbcTemplate = jdbcTemplate;
}

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

Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);

log.debug("query : {}", sql);
jdbcTemplate.update(sql, pstmt -> {
pstmt.setLong(1, userHistory.getUserId());
pstmt.setString(2, userHistory.getAccount());
pstmt.setString(3, userHistory.getPassword());
pstmt.setString(4, userHistory.getEmail());
pstmt.setObject(5, userHistory.getCreatedAt());
pstmt.setString(6, userHistory.getCreateBy());
});
}

public void log(final Connection connection, final UserHistory userHistory) {
final var sql = "insert into user_history (user_id, account, password, email, created_at, created_by) values (?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(connection, sql, pstmt -> {
pstmt.setLong(1, userHistory.getUserId());
pstmt.setString(2, userHistory.getAccount());
pstmt.setString(3, userHistory.getPassword());
pstmt.setString(4, userHistory.getEmail());
pstmt.setObject(5, userHistory.getCreatedAt());
pstmt.setString(6, userHistory.getCreateBy());
pstmt.executeUpdate();
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException ignored) {}

try {
if (conn != null) {
conn.close();
}
} catch (SQLException ignored) {}
}
});
}
}
56 changes: 51 additions & 5 deletions app/src/main/java/com/techcourse/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.domain.UserHistory;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserService {

private static final Logger log = LoggerFactory.getLogger(UserService.class);
private final DataSource dataSource;
private final UserDao userDao;
private final UserHistoryDao userHistoryDao;

public UserService(final UserDao userDao, final UserHistoryDao userHistoryDao) {
public UserService(
final DataSource dataSource,
final UserDao userDao,
final UserHistoryDao userHistoryDao
) {
this.dataSource = dataSource;
this.userDao = userDao;
this.userHistoryDao = userHistoryDao;
}
Expand All @@ -28,9 +40,43 @@ public void insert(final User user) {
}

public void changePassword(final long id, final String newPassword, final String createBy) {
final var user = findById(id);
user.changePassword(newPassword);
userDao.update(user);
userHistoryDao.log(new UserHistory(user, createBy));
Connection connection = null;
try {
connection = dataSource.getConnection();
connection.setAutoCommit(false);

final User user = findById(id);
user.changePassword(newPassword);
userDao.update(connection, user);
userHistoryDao.log(connection, new UserHistory(user, createBy));

connection.commit();
} catch (final Exception e) {
rollback(connection);
log.warn("sql 실행 중 오류 발생: rollback 완료", e);
} finally {
closeConnection(connection);
}
}

private void rollback(final Connection connection) {
try {
if (connection != null) {
connection.rollback();
}
} catch (final SQLException e) {
log.error("sql 실행 중 오류 발생: rollback 실패", e);
}
}

private void closeConnection(final Connection connection) {
try {
if (connection != null) {
connection.setAutoCommit(true);
connection.close();
}
} catch (final SQLException e) {
log.error("connection close 실패", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.techcourse.service;

import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.UserHistory;
import com.interface21.dao.DataAccessException;
import com.interface21.jdbc.core.JdbcTemplate;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.UserHistory;
import java.sql.Connection;

public class MockUserHistoryDao extends UserHistoryDao {

Expand All @@ -12,7 +13,7 @@ public MockUserHistoryDao(final JdbcTemplate jdbcTemplate) {
}

@Override
public void log(final UserHistory userHistory) {
public void log(final Connection connection, final UserHistory userHistory) {
throw new DataAccessException();
}
}
14 changes: 7 additions & 7 deletions app/src/test/java/com/techcourse/service/UserServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.techcourse.service;

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

import com.interface21.dao.DataAccessException;
import com.interface21.jdbc.core.JdbcTemplate;
import com.techcourse.config.DataSourceConfig;
import com.techcourse.dao.UserDao;
import com.techcourse.dao.UserHistoryDao;
import com.techcourse.domain.User;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import com.interface21.dao.DataAccessException;
import com.interface21.jdbc.core.JdbcTemplate;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

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

@Disabled
class UserServiceTest {

Expand All @@ -33,7 +33,7 @@ void setUp() {
@Test
void testChangePassword() {
final var userHistoryDao = new UserHistoryDao(jdbcTemplate);
final var userService = new UserService(userDao, userHistoryDao);
final var userService = new UserService(DataSourceConfig.getInstance(), userDao, userHistoryDao);

final var newPassword = "qqqqq";
final var createBy = "gugu";
Expand All @@ -48,7 +48,7 @@ void testChangePassword() {
void testTransactionRollback() {
// 트랜잭션 롤백 테스트를 위해 mock으로 교체
final var userHistoryDao = new MockUserHistoryDao(jdbcTemplate);
final var userService = new UserService(userDao, userHistoryDao);
final var userService = new UserService(DataSourceConfig.getInstance(), userDao, userHistoryDao);

final var newPassword = "newPassword";
final var createBy = "gugu";
Expand Down
55 changes: 28 additions & 27 deletions jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,34 @@ public JdbcTemplate(final DataSource dataSource) {
this.parameterBinder = ParameterBinder.init();
}

public int update(
final String sql,
final PreparedStatementSetter preparedStatementSetter
) {
return executeSql(sql, PreparedStatement::executeUpdate, preparedStatementSetter);
}

public int update(
final String sql,
final Object... parameters
) {
return executeSql(sql, PreparedStatement::executeUpdate, parameters);
return update(sql, ps -> bindParameters(ps, parameters));
}

public int update(
final Connection connection,
final String sql,
final PreparedStatementSetter preparedStatementSetter
) {
return executeSql(sql, PreparedStatement::executeUpdate, preparedStatementSetter);
return executeSql(connection, sql, PreparedStatement::executeUpdate, preparedStatementSetter);
}

public <T> List<T> query(
public int update(
final Connection connection,
final String sql,
final RowMapper<T> rowMapper,
final Object... parameters
Object... parameters
) {
return executeSql(sql, preparedStatement -> {
try (final ResultSet resultSet = preparedStatement.executeQuery()) {
final List<T> result = new ArrayList<>();
while (resultSet.next()) {
result.add(rowMapper.mapRow(resultSet));
}
return result;
}
}, parameters);
return update(connection, sql, ps -> bindParameters(ps, parameters));
}

public <T> List<T> query(
Expand All @@ -70,19 +70,12 @@ public <T> List<T> query(
}, preparedStatementSetter);
}

public <T> T queryForObject(
public <T> List<T> query(
final String sql,
final RowMapper<T> rowMapper,
final Object... parameters
) {
List<T> results = query(sql, rowMapper, parameters);
if (results.isEmpty()) {
return null;
}
if (results.size() > 1) {
throw new IncorrectResultSizeException("조회 결과 수가 2개 이상입니다: " + results.size());
}
return results.getFirst();
return query(sql, rowMapper, ps -> bindParameters(ps, parameters));
}

public <T> T queryForObject(
Expand All @@ -100,6 +93,14 @@ public <T> T queryForObject(
return results.getFirst();
}

public <T> T queryForObject(
final String sql,
final RowMapper<T> rowMapper,
final Object... parameters
) {
return queryForObject(sql, rowMapper, ps -> bindParameters(ps, parameters));
}

private <T> T executeSql(
final String sql,
final JdbcCallback<T> callback,
Expand All @@ -120,15 +121,15 @@ private <T> T executeSql(
}

private <T> T executeSql(
final Connection connection,
final String sql,
final JdbcCallback<T> callback,
final Object... parameters
final PreparedStatementSetter preparedStatementSetter
) {
try (Connection connection = dataSource.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

log.debug("query : {}", sql);
bindParameters(preparedStatement, parameters);
preparedStatementSetter.setValues(preparedStatement);

return callback.execute(preparedStatement);

Expand Down
Loading