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 라이브러리 구현하기 - 1단계] 제이미(임정수) 미션 제출합니다! #335

Merged
merged 8 commits into from
Sep 30, 2023
105 changes: 20 additions & 85 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,120 +2,55 @@

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

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class UserDao {

private static final Logger log = LoggerFactory.getLogger(UserDao.class);
private static final RowMapper<User> rowMapper = (rs, rowNum) -> new User(
rs.getLong(1),
rs.getString(2),
rs.getString(3),
rs.getString(4)
);
Comment on lines +13 to +17
Copy link

Choose a reason for hiding this comment

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

컬럼의 index와 컬럼의 name으로 추출하는 두 가지의 방법이 존재하는데 인덱스로 추출해주신 이유가 궁금합니다 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

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

기존에 코드가 그렇게 주어졌기에 크게 생각하지 않고 바로 인덱스로 추출하는 방식을 사용하게 되었습니다..!
그레이가 말씀해 주셔서 고민해 본 결과 저는 컴럼명을 통해 추출하는 방식이 보다 명확해 보여서 좋을 것 같네요.
다만, 컬럼명이 수정된다면 계속 변경해야겠지만, 그럴 일은 적을 것 같아 가독성을 선택하도록 하겠습니다!
해당 방법으로 수정해 두었습니다.

그레이는 어떤 방식으로 진행하셨고 이유가 무엇인지 궁금하네요!

Copy link

Choose a reason for hiding this comment

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

저는 컬럼 순서보다 컬럼 명이 읽기가 명확하고, 잘못된 값을 가져오는 상황을 방지할 수 있기 때문에 컬럼 명으로 가져오는 방법을 선택했씁니다 ㅎㅎ


private final DataSource dataSource;
private final JdbcTemplate jdbcTemplate;

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

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

public void insert(final User user) {
final var sql = "insert into users (account, password, email) values (?, ?, ?)";

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

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

pstmt.setString(1, user.getAccount());
pstmt.setString(2, user.getPassword());
pstmt.setString(3, user.getEmail());
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) {}
}
jdbcTemplate.update(sql, user.getAccount(), user.getPassword(), user.getEmail());
}

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

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

return jdbcTemplate.query(sql, rowMapper);
}

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

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setLong(1, id);
rs = pstmt.executeQuery();

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

if (rs.next()) {
return new User(
rs.getLong(1),
rs.getString(2),
rs.getString(3),
rs.getString(4));
}
return null;
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
} finally {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException ignored) {}

try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException ignored) {}

try {
if (conn != null) {
conn.close();
}
} catch (SQLException ignored) {}
}
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}

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

return jdbcTemplate.queryForObject(sql, rowMapper, account);
}
}
78 changes: 78 additions & 0 deletions jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import org.slf4j.LoggerFactory;

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;

public class JdbcTemplate {

Expand All @@ -14,4 +20,76 @@ public class JdbcTemplate {
public JdbcTemplate(final DataSource dataSource) {
this.dataSource = 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);
}
}

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) {
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 static <T> T calculateResult(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
Copy link

Choose a reason for hiding this comment

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

static은 삭제해도 될 것 같은데 명시해주신 이유가 궁금하네요 😄

if (rs.next()) {
return rowMapper.mapRow(rs, rs.getRow());
}
Comment on lines +63 to +65
Copy link

Choose a reason for hiding this comment

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

queryForObject에서 호출되는 메서드인데 한 건의 결과가 아닌 경우 적절히 예외 처리를 해줘도 좋을 것 같아요 !! ㅎㅎ


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 static <T> List<T> getResults(final RowMapper<T> rowMapper, final ResultSet rs) throws SQLException {
List<T> results = new ArrayList<>();

while (rs.next()) {
final T result = calculateResult(rowMapper, rs);
results.add(result);
}

return results;
}
}
10 changes: 10 additions & 0 deletions jdbc/src/main/java/org/springframework/jdbc/core/RowMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.springframework.jdbc.core;

import java.sql.ResultSet;
import java.sql.SQLException;

@FunctionalInterface
public interface RowMapper<T> {

T mapRow(final ResultSet rs, final int rowNum) throws SQLException;
Copy link

@Kim0914 Kim0914 Sep 30, 2023

Choose a reason for hiding this comment

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

제가 1단계를 진행하면서 느낀 궁금점인데요 !

RowMapper에서 rowNum은 어떤 역할을 하는 파라미터일까요?!

Copy link
Member Author

Choose a reason for hiding this comment

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

해당 파라미터는 그랬던 것 같아서 넣은 거였는데 제가 전혀 사용하지 않는군요..!
찾아보니 반복되는 결과 집합에서 행 번호를 나타낸다고 하네요.
그런데, 해당 파라미터를 현재 로직에서 어떻게 사용해야 할지 감이 오지 않기도 하고, 현재는 사용하지 않기에 제거했습니다.

}
Loading