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단계] 에버(손채영) 미션 제출합니다. #645

Merged
merged 11 commits into from
Oct 7, 2024
Merged
107 changes: 18 additions & 89 deletions app/src/main/java/com/techcourse/dao/UserDao.java
Original file line number Diff line number Diff line change
@@ -1,121 +1,50 @@
package com.techcourse.dao;

import com.techcourse.domain.User;
import com.interface21.jdbc.core.JdbcTemplate;
import com.interface21.jdbc.core.RowMapper;
import com.techcourse.domain.User;
import java.util.List;
import org.slf4j.Logger;
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.List;

public class UserDao {

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

private final DataSource dataSource;
private static final RowMapper<User> USER_ROW_MAPPER = (rs) -> new User(
rs.getLong("id"),
rs.getString("account"),
rs.getString("password"),
rs.getString("email"));

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

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.executeUpdate(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.executeUpdate(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.executeQuery(sql, USER_ROW_MAPPER);
}

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.executeQueryForObject(sql, USER_ROW_MAPPER, id);
}

public User findByAccount(final String account) {
// todo
return null;
final var sql = "select id, account, password, email from users where account = ?";
return jdbcTemplate.executeQueryForObject(sql, USER_ROW_MAPPER, account);
}
}
17 changes: 9 additions & 8 deletions app/src/test/java/com/techcourse/dao/UserDaoTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.techcourse.dao;

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

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

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

class UserDaoTest {

private UserDao userDao;
Expand All @@ -16,8 +17,8 @@ class UserDaoTest {
void setup() {
DatabasePopulatorUtils.execute(DataSourceConfig.getInstance());

userDao = new UserDao(DataSourceConfig.getInstance());
final var user = new User("gugu", "password", "hkkang@woowahan.com");
userDao = new UserDao(new JdbcTemplate(DataSourceConfig.getInstance()));
final var user = new User("ever", "password", "ever@woowahan.com");
userDao.insert(user);
}

Expand All @@ -32,21 +33,21 @@ void findAll() {
void findById() {
final var user = userDao.findById(1L);

assertThat(user.getAccount()).isEqualTo("gugu");
assertThat(user.getAccount()).isEqualTo("ever");
}

@Test
void findByAccount() {
final var account = "gugu";
final var account = "ever";
final var user = userDao.findByAccount(account);

assertThat(user.getAccount()).isEqualTo(account);
}

@Test
void insert() {
final var account = "insert-gugu";
final var user = new User(account, "password", "hkkang@woowahan.com");
final var account = "insert-ever";
final var user = new User(account, "password", "ever@woowahan.com");
userDao.insert(user);

final var actual = userDao.findById(2L);
Expand Down
139 changes: 137 additions & 2 deletions jdbc/src/main/java/com/interface21/jdbc/core/JdbcTemplate.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package com.interface21.jdbc.core;

import com.interface21.dao.DataAccessException;
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 javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;

public class JdbcTemplate {
Copy link

Choose a reason for hiding this comment

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

아직 리팩토링이 되지 않았더라도 테스트를 작성해보면 어떨까요?

저는 주로 테스트를 작성하면서 객체의 역할이 명확한지 한번 더 확인하게 되는 것 같아요.
이번 단계에 테스트를 작성해둔다면 다음 단계에서 리팩토링할 때, JdbcTemplate가 어떤 역할을 가진 객체이고 역할이 너무 많은 건 아닌가 파악하기 수월할 것 같습니다 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

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

동의합니다아 급하게 구현하여 제출하다보니 마음이 급해져 가장 중요한 테스트 작성을 잊었어요


private static final Logger log = LoggerFactory.getLogger(JdbcTemplate.class);
Expand All @@ -14,4 +20,133 @@ public class JdbcTemplate {
public JdbcTemplate(final DataSource dataSource) {
this.dataSource = dataSource;
}

public void executeUpdate(String sql, Object... parameters) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);

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

setParameter(pstmt, parameters);
pstmt.executeUpdate();

} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(e);
} finally {
try {
if (pstmt != null) {
pstmt.close();
}
} catch (SQLException ignored) {
}

try {
if (conn != null) {
conn.close();
}
} catch (SQLException ignored) {
}
jminkkk marked this conversation as resolved.
Show resolved Hide resolved
}
}

public <T> T executeQueryForObject(String sql, RowMapper<T> rowMapper, Object... parameters) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
pstmt = conn.prepareStatement(sql);

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

setParameter(pstmt, parameters);
rs = pstmt.executeQuery();

if (!rs.next()) {
return null;
}
return rowMapper.mapRow(rs);

} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(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) {
}
}
}

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

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

setParameter(pstmt, parameters);
rs = pstmt.executeQuery();

List<T> result = new ArrayList<>();
while (rs.next()) {
result.add(rowMapper.mapRow(rs));
}
return result;

} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(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) {
}
}
}

private void setParameter(PreparedStatement pstmt, Object[] parameters) throws SQLException {
for (int i = 0; i < parameters.length; i++) {
pstmt.setObject(i + 1, parameters[i]);
}
}
}
9 changes: 9 additions & 0 deletions jdbc/src/main/java/com/interface21/jdbc/core/RowMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.interface21.jdbc.core;

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

@FunctionalInterface
public interface RowMapper<T> {
T mapRow(ResultSet rs) throws SQLException;
}
Loading