-
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 라이브러리 구현하기 - 1단계] 헙크(정현승) 미션 제출합니다. #294
Changes from all commits
4d32d5f
7bf90f8
b7063c3
875b5b4
9faa5c6
c89e572
db5f5fd
2cd6c77
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 |
---|---|---|
@@ -1,121 +1,54 @@ | ||
package com.techcourse.dao; | ||
|
||
import com.techcourse.domain.User; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
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; | ||
import java.util.Optional; | ||
|
||
public class UserDao { | ||
private static final RowMapper<User> USER_ROW_MAPPER = rs -> new User( | ||
rs.getLong("id"), | ||
rs.getString("account"), | ||
rs.getString("password"), | ||
rs.getString("email") | ||
); | ||
|
||
private static final Logger log = LoggerFactory.getLogger(UserDao.class); | ||
private final JdbcTemplate template; | ||
|
||
private final DataSource dataSource; | ||
|
||
public UserDao(final DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public UserDao(final JdbcTemplate jdbcTemplate) { | ||
this.dataSource = null; | ||
public UserDao(final JdbcTemplate template) { | ||
this.template = template; | ||
} | ||
|
||
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) {} | ||
} | ||
template.update(sql, user.getAccount(), user.getPassword(), user.getEmail()); | ||
} | ||
|
||
public void update(final User user) { | ||
// todo | ||
final var sql = "update users set password = ? where id = ?"; | ||
template.update(sql, user.getPassword(), user.getId()); | ||
} | ||
|
||
public List<User> findAll() { | ||
// todo | ||
return null; | ||
final String sql = "select id, account, password, email from users"; | ||
return template.query(sql, userRowMapper()); | ||
} | ||
|
||
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) {} | ||
public Optional<User> findById(final Long id) { | ||
final String sql = "select id, account, password, email from users where id = ?"; | ||
return template.queryForObject(sql, userRowMapper(), id); | ||
} | ||
|
||
try { | ||
if (conn != null) { | ||
conn.close(); | ||
} | ||
} catch (SQLException ignored) {} | ||
} | ||
public Optional<User> findByAccount(final String account) { | ||
final String sql = "select id, account, password, email from users where account = ?"; | ||
return template.queryForObject(sql, userRowMapper(), account); | ||
} | ||
|
||
public User findByAccount(final String account) { | ||
// todo | ||
return null; | ||
private RowMapper<User> userRowMapper() { | ||
return USER_ROW_MAPPER; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import com.techcourse.support.jdbc.init.DatabasePopulatorUtils; | ||
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; | ||
|
||
|
@@ -16,7 +17,7 @@ class UserDaoTest { | |
void setup() { | ||
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance()); | ||
|
||
userDao = new UserDao(DataSourceConfig.getInstance()); | ||
userDao = new UserDao(new JdbcTemplate(DataSourceConfig.getInstance())); | ||
final var user = new User("gugu", "password", "[email protected]"); | ||
userDao.insert(user); | ||
} | ||
|
@@ -30,15 +31,15 @@ void findAll() { | |
|
||
@Test | ||
void findById() { | ||
final var user = userDao.findById(1L); | ||
final var user = userDao.findById(1L).orElseThrow(); | ||
|
||
assertThat(user.getAccount()).isEqualTo("gugu"); | ||
} | ||
|
||
@Test | ||
void findByAccount() { | ||
final var account = "gugu"; | ||
final var user = userDao.findByAccount(account); | ||
final var user = userDao.findByAccount(account).orElseThrow(); | ||
|
||
assertThat(user.getAccount()).isEqualTo(account); | ||
} | ||
|
@@ -49,20 +50,20 @@ void insert() { | |
final var user = new User(account, "password", "[email protected]"); | ||
userDao.insert(user); | ||
|
||
final var actual = userDao.findById(2L); | ||
final var actual = userDao.findById(2L).orElseThrow(); | ||
|
||
assertThat(actual.getAccount()).isEqualTo(account); | ||
} | ||
|
||
@Test | ||
void update() { | ||
final var newPassword = "password99"; | ||
final var user = userDao.findById(1L); | ||
user.changePassword(newPassword); | ||
final var user = userDao.findById(1L).orElseThrow(); | ||
|
||
user.changePassword(newPassword); | ||
userDao.update(user); | ||
|
||
final var actual = userDao.findById(1L); | ||
final var actual = userDao.findById(1L).orElseThrow(); | ||
|
||
assertThat(actual.getPassword()).isEqualTo(newPassword); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,65 @@ | ||
package org.springframework.jdbc.core; | ||
|
||
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; | ||
|
||
public JdbcTemplate(final DataSource dataSource) { | ||
this.dataSource = dataSource; | ||
} | ||
|
||
public <T> Optional<T> queryForObject(final String sql, final RowMapper<T> rowMapper, Object... args) { | ||
try (final Connection conn = dataSource.getConnection(); | ||
final PreparedStatement pstmt = conn.prepareStatement(sql)) { | ||
for (int i = 0; i < args.length; i++) { | ||
pstmt.setObject(i + 1, args[i]); | ||
} | ||
try (final ResultSet rs = pstmt.executeQuery()) { | ||
if (rs.next()) { | ||
return Optional.ofNullable(rowMapper.mapRow(rs)); | ||
} | ||
return Optional.empty(); | ||
} | ||
} catch (final SQLException e) { | ||
throw new DataAccessException(e); | ||
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. DataAccessException으로 바꿔 던지는거 좋습니다👍 |
||
} | ||
} | ||
|
||
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException { | ||
try (final Connection conn = dataSource.getConnection(); | ||
final PreparedStatement pstmt = conn.prepareStatement(sql)) { | ||
final List<T> result = new ArrayList<>(); | ||
try (final ResultSet rs = pstmt.executeQuery()) { | ||
if (rs.next()) { | ||
result.add(rowMapper.mapRow(rs)); | ||
} | ||
return result; | ||
} | ||
|
||
} catch (final SQLException e) { | ||
throw new DataAccessException(e); | ||
} | ||
} | ||
|
||
public int update(final String sql, final Object... args) { | ||
try (final Connection conn = dataSource.getConnection(); | ||
final PreparedStatement pstmt = conn.prepareStatement(sql)) { | ||
for (int i = 0; i < args.length; i++) { | ||
pstmt.setObject(i + 1, args[i]); | ||
} | ||
Comment on lines
+57
to
+59
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. 메서드를 추출한다면 해당 메서드로 이동하여 로직을 파악하여야 하기 때문에, 전체적인 코드의 맥락을 바로 파악하기엔 추출하지 않는 것도 좋다고 생각합니다 ㅎㅎㅎ 조금 더 복잡한 로직이었더라면 메서드로 추출하고 네이밍을 주어 가독성을 높일 수 있을 것 같다는 생각을 했습니다. 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. 좋습니다! 확실히 가독성이 떨어지긴 하죠! |
||
return pstmt.executeUpdate(); | ||
} catch (final SQLException e) { | ||
throw new DataAccessException(e); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.springframework.jdbc.core; | ||
|
||
import javax.annotation.Nullable; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
|
||
@FunctionalInterface | ||
public interface RowMapper<T> { | ||
|
||
@Nullable | ||
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. Nullable을 붙이신 이유가 따로 있을까요?(진짜 궁금) 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. 반환값이 null 이 될 수도 있다는 뜻이었군요! 배워갑니다~😄 |
||
T mapRow(ResultSet rs) throws SQLException; | ||
|
||
} |
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.
nullable 좋네요👍👍