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단계] 망고(고재철) 미션 제출합니다. #331

Merged
merged 3 commits into from
Sep 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 18 additions & 86 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,52 @@

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 final RowMapper<User> rowMapper = resultSet -> new User(
resultSet.getLong("id"),
resultSet.getString("account"),
resultSet.getString("password"),
resultSet.getString("email")
);

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 = ?";

Choose a reason for hiding this comment

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

Suggested change
final var sql = "update users set account = ?, password = ?, email = ? where id = ?";
final var sql = "update users set (account, password, email) = (?, ?, ?) where id = ?";

저도 매인고처럼 작성했었는데 피드백 받고나니 Insert할 때처럼 update도 이런 식으로 해봐도 같아요!

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);
}
}
57 changes: 57 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 @@ -2,8 +2,14 @@

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.SQLException;
import java.util.ArrayList;
import java.util.List;

public class JdbcTemplate {

Expand All @@ -14,4 +20,55 @@ public class JdbcTemplate {
public JdbcTemplate(final DataSource dataSource) {
this.dataSource = dataSource;
}

public void update(final String sql, final Object... objects) {
try (final var connection = dataSource.getConnection();
final var preparedStatement = prepareStatement(connection, sql, objects)) {
log.debug("query : {}", sql);
preparedStatement.executeUpdate();
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(e);
}
}

public <T> T queryForObject(final String sql, final RowMapper<T> rowMapper, final Object... objects) {
try (final var connection = dataSource.getConnection();
final var preparedStatement = prepareStatement(connection, sql, objects);
final var resultSet = preparedStatement.executeQuery()) {
log.debug("query : {}", sql);
if (resultSet.next()) {
return rowMapper.mapRow(resultSet);
}
return null;
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(e);
}
}

public <T> List<T> query(final String sql, final RowMapper<T> rowMapper) {
try (final var connection = dataSource.getConnection();
final var preparedStatement = connection.prepareStatement(sql);
final var resultSet = preparedStatement.executeQuery()) {
log.debug("query : {}", sql);
final var results = new ArrayList<T>();
while (resultSet.next()) {
results.add(rowMapper.mapRow(resultSet));
}
return results;
} catch (SQLException e) {
log.error(e.getMessage(), e);
throw new DataAccessException(e);
}
}

private PreparedStatement prepareStatement(final Connection connection, final String sql, final Object[] objects)

Choose a reason for hiding this comment

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

여기는 개인적인 생각이지만 기존 connection.prepareStatement()와 같은 메서드명이라 순간적으로 objects를 어디서 주입하는거지라는 생각을 하게됐습니다!

하지만 자연스럽게 읽혔다는 장점도 있어서 좋았습니다 👍👍👍👍

throws SQLException {
final var preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < objects.length; i++) {
preparedStatement.setObject(i + 1, objects[i]);
}
return preparedStatement;
}
}
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

Choose a reason for hiding this comment

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

RowMapper에 '@FunctionalInterface'로 어노테이션을 추가하신 이유가 궁금합니다 🥭

저는 해당 어노테이션을 다는 이유가 함수형으로 사용할 때 컴파일러가 추론하기 위해 컴파일 시점에 추상메서드가 하나만 존재하는지 확인하기 위함으로 알고 있습니다!

Choose a reason for hiding this comment

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

갑자기 생각들었는데 함수로 사용하고 있는게 맞는데 제가 이상한 커멘트를 달았네요! 이 커멘트는 무시해주시길..!!

public interface RowMapper<T> {

T mapRow(final ResultSet resultSet) throws SQLException;
}
1 change: 1 addition & 0 deletions study/src/main/java/aop/config/DataSourceConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class DataSourceConfig {
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("test;DB_CLOSE_DELAY=-1;MODE=MYSQL;")
.addScript("classpath:schema.sql")
.build();
}
Expand Down
1 change: 1 addition & 0 deletions study/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
spring:
jpa:
open-in-view: false
show-sql: true
generate-ddl: true
hibernate:
Expand Down
Loading