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 라이브러리 구현하기 - 2단계] 바론(이소민) 미션 제출합니다. #385

Merged
merged 9 commits into from
Oct 6, 2023
16 changes: 13 additions & 3 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.techcourse.dao;

import com.techcourse.dao.exception.UserNotExistException;
import com.techcourse.domain.User;
import java.util.List;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class UserDao {

private static final RowMapper<User> ROW_MAPPER = (rs, count) ->
private static final RowMapper<User> ROW_MAPPER = rs ->
new User(
rs.getLong("id"),
rs.getString("account"),
Expand Down Expand Up @@ -42,12 +44,20 @@ public List<User> findAll() {
public User findById(final Long id) {
final String sql = "select id, account, password, email from users where id = ?";

return jdbcTemplate.queryForObject(sql, ROW_MAPPER, id);
try {
return jdbcTemplate.queryForObject(sql, ROW_MAPPER, id);
} catch (EmptyResultDataAccessException e) {
throw new UserNotExistException();
}
somsom13 marked this conversation as resolved.
Show resolved Hide resolved
}

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

return jdbcTemplate.queryForObject(sql, ROW_MAPPER, account);
try {
return jdbcTemplate.queryForObject(sql, ROW_MAPPER, account);
} catch (EmptyResultDataAccessException e) {
throw new UserNotExistException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.techcourse.dao.exception;

public class UserNotExistException extends RuntimeException {

public UserNotExistException() {
super("존재하지 않는 사용자입니다.");
}
}
11 changes: 9 additions & 2 deletions app/src/test/java/com/techcourse/dao/UserDaoTest.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package com.techcourse.dao;

import static org.assertj.core.api.Assertions.assertThat;

import com.techcourse.config.DataSourceConfig;
import com.techcourse.domain.User;
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;

import static org.assertj.core.api.Assertions.assertThat;

class UserDaoTest {

private UserDao userDao;
Expand All @@ -22,6 +23,12 @@ void setup() {
userDao.insert(user);
}

@AfterEach
void tearDown() {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(DataSourceConfig.getInstance());
jdbcTemplate.update("TRUNCATE TABLE `users` RESTART IDENTITY");
}

@Test
void findAll() {
final var users = userDao.findAll();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.springframework.dao;

public class EmptyDataAccessException extends DataAccessException {

public EmptyDataAccessException() {
super("조회 결과가 없습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.springframework.dao;

public class IncorrectResultSizeDataAccessException extends DataAccessException {

public IncorrectResultSizeDataAccessException(final int expected, final int actual) {
super(String.format("의도한 것과 다른 개수의 데이터가 조회되었습니다. Expected: %d, Actual: %d", expected, actual));
}
}
72 changes: 34 additions & 38 deletions jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;

public class JdbcTemplate {

Expand All @@ -20,60 +23,53 @@ public JdbcTemplate(final DataSource dataSource) {
this.dataSource = dataSource;
}

public <T> List<T> query(final String sql, final RowMapper<T> rowMapper, final Object... args) {
try (final Connection connection = dataSource.getConnection();
final PreparedStatement pstmt = connection.prepareStatement(sql)) {
log.debug("query : {}", sql);
public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... args) {
final List<T> results = query(sql, rowMapper, args);

setParamsToPreparedStatement(pstmt, args);
if (results.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, results.size());
}
if (results.isEmpty()) {
throw new EmptyDataAccessException();
}

return results.get(0);
}

public <T> List<T> query(final String sql, final RowMapper<T> rowMapper, final Object... args) {
return executeInternal(sql, pstmt -> {
final ResultSet resultSet = pstmt.executeQuery();
final List<T> results = new ArrayList<>();
if (resultSet.next()) {
results.add(rowMapper.mapRow(resultSet, resultSet.getRow()));

while (resultSet.next()) {
results.add(rowMapper.mapRow(resultSet));
}

Comment on lines 41 to 47

Choose a reason for hiding this comment

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

ㄹ리뷰 반영해 주셔서👍🏻👍🏻

return results;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

private void setParamsToPreparedStatement(final PreparedStatement pstmt, final Object[] args)
throws SQLException
{
for (int i = 0; i < args.length; i++) {
pstmt.setObject(i + 1, args[i]);
}
}, args);
}

public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... args) {
try (final Connection connection = dataSource.getConnection();
final PreparedStatement pstmt = connection.prepareStatement(sql)) {
private <T> T executeInternal(final String sql, final QueryExecutor<T> executor, final Object... args) {
try (
final Connection connection = dataSource.getConnection();
final PreparedStatement pstmt = connection.prepareStatement(sql)
) {
log.debug("query : {}", sql);

setParamsToPreparedStatement(pstmt, args);
somsom13 marked this conversation as resolved.
Show resolved Hide resolved

final ResultSet resultSet = pstmt.executeQuery();
if (resultSet.next()) {
return rowMapper.mapRow(resultSet, resultSet.getRow());
}
return null;
return executor.run(pstmt);
} catch (SQLException e) {
throw new RuntimeException(e);
throw new DataAccessException(e);
}
}

public int update(final String sql, final Object... args) {
try (final Connection connection = dataSource.getConnection();
final PreparedStatement pstmt = connection.prepareStatement(sql)) {
log.debug("query : {}", sql);

setParamsToPreparedStatement(pstmt, args);

return pstmt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
private void setParamsToPreparedStatement(final PreparedStatement pstmt, final Object[] args) throws SQLException {
for (int i = 0; i < args.length; i++) {
pstmt.setObject(i + 1, args[i]);
}
}

public int update(final String sql, final Object... args) {
return executeInternal(sql, PreparedStatement::executeUpdate, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.springframework.jdbc.core;

import java.sql.PreparedStatement;
import java.sql.SQLException;

@FunctionalInterface
public interface QueryExecutor<T> {

T run(final PreparedStatement pstmt) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
@FunctionalInterface
public interface RowMapper<T> {

T mapRow(final ResultSet resultSet, final int count) throws SQLException;
T mapRow(final ResultSet resultSet) throws SQLException;
}
Loading