-
Notifications
You must be signed in to change notification settings - Fork 300
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단계] 채채(신채원) 미션 제출합니다. #467
Changes from all commits
c536c6c
56efd50
4a25fa1
12c3b65
b4700c8
0780999
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,83 +2,72 @@ | |
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.dao.DataAccessException; | ||
|
||
import javax.sql.DataSource; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public class JdbcTemplate { | ||
|
||
private static final Logger log = LoggerFactory.getLogger(JdbcTemplate.class); | ||
|
||
private final DataSource dataSource; | ||
private final StatementExecutor statementExecutor; | ||
|
||
public JdbcTemplate(final DataSource dataSource) { | ||
this(dataSource, new StatementExecutor()); | ||
} | ||
|
||
public JdbcTemplate(final DataSource dataSource, | ||
final StatementExecutor statementExecutor) { | ||
this.dataSource = dataSource; | ||
this.statementExecutor = statementExecutor; | ||
} | ||
|
||
public void update(final String sql, | ||
final Object... parameters) { | ||
try (final Connection connection = dataSource.getConnection(); | ||
final PreparedStatement preparedStatement = getPreparedStatement(sql, connection, parameters)) { | ||
log.debug("query : {}", sql); | ||
for (int i = 0; i < parameters.length; i++) { | ||
preparedStatement.setObject(i + 1, parameters[i]); | ||
} | ||
preparedStatement.executeUpdate(); | ||
} catch (SQLException e) { | ||
log.error(e.getMessage(), e); | ||
throw new RuntimeException(e); | ||
public void update(final String sql, final Object... parameters) { | ||
query(sql, PreparedStatement::executeUpdate, parameters); | ||
} | ||
|
||
public <T> Optional<T> queryForObject(final String sql, final ResultSetMapper<T> rowMapper, final Object... parameters) { | ||
final List<T> results = query(sql, statement -> statementExecutor.execute(statement, rowMapper), parameters); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 채채가 작성해주신 queryForObject 에는 결과의 수를 검증하는 부분이 있으니, 이 메서드에서 queryForList를 재사용해서 중복을 줄여도 괜찮을 것 같다는 생각이 드네요. |
||
if (results.size() > 1) { | ||
throw new DataAccessException("2개 이상의 결과를 반환할 수 없습니다."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 유저에게 상세한 unchckedException으로 변환해 던져 주셨네요 👍 그런데 JDBC Template 같은 라이브러리의 코드를 보면 메서드들이 UnchckedException 인데도 불구하고 이러런식으로 메서드 시그니처에 throws 가 붙어있는 것을 확인할 수 있습니다. 저도 왜 굳이 던져주는지 궁금해서 찾아봤는데 스택 오버플로우 에서 이런 의견이 있더라고요.
대충 명시적으로 사용자가 어떤 예외가 던져지는지 알게 하고, 처리를 어떻게 할 것인지는 자유에 맡긴다는 뜻 같아요! |
||
} | ||
if (results.isEmpty()) { | ||
return Optional.empty(); | ||
} | ||
|
||
return Optional.ofNullable(results.iterator().next()); | ||
Comment on lines
+40
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에서 Empty를 검증하는데도 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional은 항상 ofNullable를 사용하였어서 습관처럼 사용하였네요 말씀처럼 위에서 체크를 해주었기 때문에 of로 하는 것이 더 좋을 것 같습니다! |
||
} | ||
|
||
public <T> T queryForObject(final String sql, | ||
final ResultSetMapper<T> rowMapper, | ||
final Object... parameters) { | ||
public <T> List<T> queryForList(final String sql, final ResultSetMapper<T> rowMapper, final Object... parameters) { | ||
return query(sql, statement -> statementExecutor.execute(statement, rowMapper), parameters); | ||
} | ||
|
||
private <T> T query(final String sql, | ||
final PreparedStatementCallback<T> preparedStatementCallback, | ||
final Object... parameters) { | ||
try (final Connection connection = dataSource.getConnection(); | ||
final PreparedStatement preparedStatement = getPreparedStatement(sql, connection, parameters); | ||
final ResultSet resultSet = preparedStatement.executeQuery()) { | ||
log.debug("query : {}", sql); | ||
if (resultSet.next()) { | ||
return rowMapper.apply(resultSet); | ||
} | ||
return null; | ||
} catch (SQLException e) { | ||
final PreparedStatement preparedStatement = statementCreate(connection, sql, parameters)) { | ||
return preparedStatementCallback.execute(preparedStatement); | ||
} catch (final SQLException e) { | ||
log.error(e.getMessage(), e); | ||
throw new RuntimeException(e); | ||
throw new DataAccessException(e); | ||
} | ||
} | ||
|
||
private PreparedStatement getPreparedStatement(final String sql, | ||
final Connection connection, | ||
final Object[] parameters) throws SQLException { | ||
private PreparedStatement statementCreate(final Connection connection, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저는 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 꼼꼼하시군여 |
||
final String sql, | ||
final Object[] parameters) throws SQLException { | ||
final PreparedStatement preparedStatement = connection.prepareStatement(sql); | ||
for (int i = 0; i < parameters.length; i++) { | ||
preparedStatement.setObject(i + 1, parameters[i]); | ||
} | ||
return preparedStatement; | ||
} | ||
|
||
public <T> List<T> queryForList(final String sql, | ||
final ResultSetMapper<T> rowMapper, | ||
final Object... parameters) { | ||
try (final Connection connection = dataSource.getConnection(); | ||
final PreparedStatement preparedStatement = getPreparedStatement(sql, connection, parameters); | ||
final ResultSet resultSet = preparedStatement.executeQuery()) { | ||
log.debug("query : {}", sql); | ||
final List<T> result = new ArrayList<>(); | ||
while (resultSet.next()) { | ||
result.add(rowMapper.apply(resultSet)); | ||
} | ||
return result; | ||
} catch (SQLException e) { | ||
log.error(e.getMessage(), e); | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.springframework.jdbc.core; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.SQLException; | ||
|
||
@FunctionalInterface | ||
public interface PreparedStatementCallback<T> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 템플릿 콜백 패턴으로 중복 코드 제거해주셨군요 👍 |
||
T execute(final PreparedStatement preparedStatement) throws SQLException; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.springframework.jdbc.core; | ||
|
||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class StatementExecutor { | ||
|
||
public <T> List<T> execute(final PreparedStatement preparedStatement, | ||
final ResultSetMapper<T> rowMapper) throws SQLException { | ||
final ResultSet resultSet = preparedStatement.executeQuery(); | ||
final List<T> results = new ArrayList<>(); | ||
while (resultSet.next()) { | ||
results.add(rowMapper.apply(resultSet)); | ||
} | ||
return results; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
app단의 코드까지 신경써주셨네요 👍