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단계] 제이미(임정수) 미션 제출합니다. #432

Merged
merged 10 commits into from
Oct 7, 2023
10 changes: 5 additions & 5 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@

public class UserDao {

private static final RowMapper<User> rowMapper = (rs, rowNum) -> new User(
rs.getLong(1),
rs.getString(2),
rs.getString(3),
rs.getString(4)
private static final RowMapper<User> rowMapper = (rs) -> new User(
rs.getLong("id"),
rs.getString("account"),
rs.getString("password"),
rs.getString("email")
Comment on lines +12 to +16
Copy link

Choose a reason for hiding this comment

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

👍

);

private final JdbcTemplate jdbcTemplate;
Expand Down
99 changes: 41 additions & 58 deletions jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.springframework.jdbc.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.exception.EmptyResultDataAccessException;
import org.springframework.jdbc.core.exception.IncorrectResultSizeDataAccessException;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
Expand All @@ -13,83 +12,67 @@

public class JdbcTemplate {

private static final Logger log = LoggerFactory.getLogger(JdbcTemplate.class);
public static final int MAX_RESULT_SIZE = 1;
public static final int FIRST_INDEX = 0;

private final DataSource dataSource;
private final PreparedStatementExecutor preparedStatementExecutor;

public JdbcTemplate(final DataSource dataSource) {
this.dataSource = dataSource;
this.preparedStatementExecutor = new PreparedStatementExecutor(dataSource);
}

public int update(final String sql, final Object... args) {
try (
final Connection conn = dataSource.getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql)
) {
setArguments(pstmt, args);

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

return pstmt.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
return preparedStatementExecutor.execute(PreparedStatement::executeUpdate, sql, args);
}

private static void setArguments(final PreparedStatement pstmt, final Object[] args) throws SQLException {
for (int i = 0; i < args.length; i++) {
final int parameterIndex = i + 1;
pstmt.setObject(parameterIndex, args[i]);
}
public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... args) {
return preparedStatementExecutor.execute(
pstmt -> {
final ResultSet rs = pstmt.executeQuery();
final List<T> results = getResults(rowMapper, rs);

return getSingleResult(results);
}, sql, args
Comment on lines +30 to +35
Copy link

Choose a reason for hiding this comment

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

익명 함수를 잘 사용해주셨네요 !

);
}

public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... args) {
try (
final Connection conn = dataSource.getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql)
) {
setArguments(pstmt, args);
ResultSet rs = pstmt.executeQuery();

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

return calculateResult(rowMapper, rs);
} catch (SQLException e) {
throw new RuntimeException(e);
private <T> List<T> getResults(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
final List<T> results = new ArrayList<>();

while (rs.next()) {
final T result = calculateResult(rowMapper, rs);
Copy link

Choose a reason for hiding this comment

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

while(rs.next())로 resultSet의 row가 있는지 확인한 상태인데 다시 calculateResult 메서드 내에서 rs.next()를 확인하는 이유가 궁금합니다 :)

바로 rowMapper.mapRow(rs)를 실행시키면 어떤 문제가 발생하나요 ?!😁

Copy link
Member Author

Choose a reason for hiding this comment

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

헉... 아무 문제도 없습니다... 🫢
당시 위와 같이 짰던 이유가 잘 기억이 안 나네요...
덕분에 수정했습니다. 감사합니다!

results.add(result);
}

return results;
}

private static <T> T calculateResult(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
private <T> T calculateResult(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
if (rs.next()) {
return rowMapper.mapRow(rs, rs.getRow());
return rowMapper.mapRow(rs);
}

return null;
}

public <T> List<T> query(final String sql, final RowMapper<T> rowMapper) {
try (
final Connection conn = dataSource.getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql)
) {
ResultSet rs = pstmt.executeQuery();

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

return getResults(rowMapper, rs);
} catch (SQLException e) {
throw new RuntimeException(e);
private <T> T getSingleResult(final List<T> results) {
if (results.isEmpty()) {
throw new EmptyResultDataAccessException("조회된 결과가 존재하지 않습니다.");
}
if (results.size() > MAX_RESULT_SIZE) {
throw new IncorrectResultSizeDataAccessException("조회된 결과의 개수가 적절하지 않습니다.");
}
}

private static <T> List<T> getResults(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
List<T> results = new ArrayList<>();
return results.get(FIRST_INDEX);
}

while (rs.next()) {
final T result = calculateResult(rowMapper, rs);
results.add(result);
}
public <T> List<T> query(final String sql, final RowMapper<T> rowMapper) {
return preparedStatementExecutor.execute(
pstmt -> {
final ResultSet rs = pstmt.executeQuery();

return results;
return getResults(rowMapper, rs);
}, sql
);
}
}
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 PreparedStatementExecuteStrategy<T> {

T strategy(final PreparedStatement pstmt) throws SQLException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.springframework.jdbc.core;

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 PreparedStatementExecutor {

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

private final DataSource dataSource;

public PreparedStatementExecutor(final DataSource dataSource) {
this.dataSource = dataSource;
}

public <T> T execute(final PreparedStatementExecuteStrategy<T> executeStrategy, final String sql, final Object... args) {
try (
final Connection conn = dataSource.getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql)
) {
setArguments(pstmt, args);

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

return executeStrategy.strategy(pstmt);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

private void setArguments(final PreparedStatement pstmt, final Object[] args) throws SQLException {
for (int i = 0; i < args.length; i++) {
final int parameterIndex = i + 1;
pstmt.setObject(parameterIndex, args[i]);
}
}
}
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 rs, final int rowNum) throws SQLException;
T mapRow(final ResultSet rs) throws SQLException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.springframework.jdbc.core.exception;

import org.springframework.dao.DataAccessException;

public class EmptyResultDataAccessException extends DataAccessException {

public EmptyResultDataAccessException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.springframework.jdbc.core.exception;

import org.springframework.dao.DataAccessException;

public class IncorrectResultSizeDataAccessException extends DataAccessException {

public IncorrectResultSizeDataAccessException(final String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.springframework.jdbc.core.exception;

public class ResultSetOverflowException extends IllegalArgumentException {

public ResultSetOverflowException(final String message) {
super(message);
}
}
Loading