Spring

Jdbc 반복 문제 해결 -JdbcTemplate

최MAX 2023. 2. 20. 16:04

MemberRepository 인터페이스

package hello.jdbc.repository;

import hello.jdbc.domain.Member;

public interface MemberRepository {

    Member save(Member member);
    Member findById(String memberId);
    void update(String memberId, int money);
    void delete(String memberId);
}

MemberRepositoryV4.class

@Slf4j
public class MemberRepositoryV4 implements MemberRepository{

    private final DataSource dataSource;

    public MemberRepositoryV4(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Member save(Member member) {
        String sql = "insert into member(member_id, money) values (?, ?)";

        Connection con = null;
        PreparedStatement pstmt = null;

        try {
            con = getConnection();
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1, member.getMemberId());
            pstmt.setInt(2, member.getMoney());
            pstmt.executeUpdate();
            return member;
        } catch (SQLException e) {
            throw new MyDbException(e);
        } finally {
            close(con, pstmt, null);
        }
    }

    @Override
    public Member findById(String memberId) {
        String sql = "select * from member where member_id = ?";

        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            con = getConnection();
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1, memberId);

            rs = pstmt.executeQuery();
            if (rs.next()) {
                Member member = new Member();
                member.setMemberId(rs.getString("member_id"));
                member.setMoney(rs.getInt("money"));
                return member;
            } else {
                throw new NoSuchElementException("member not found memberId=" + memberId);
            }
        } catch (SQLException e) {
            throw new MyDbException(e);
        } finally {
            close(con, pstmt, rs);
        }
    }

    @Override
    public void update(String memberId, int money) {
        String sql = "update member set money=? where member_id=?";

        Connection con = null;
        PreparedStatement pstmt = null;

        try {
            con = getConnection();
            pstmt = con.prepareStatement(sql);
            pstmt.setInt(1, money);
            pstmt.setString(2, memberId);
            int resultSize = pstmt.executeUpdate();
            log.info("resultSize={}", resultSize);
        } catch (SQLException e) {
            throw new MyDbException(e);
        } finally {
            close(con, pstmt, null);
        }
    }

    @Override
    public void delete(String memberId) {
        String sql = "delete from member where member_id = ?";

        
    }

    private void close(Connection con, Statement stmt, ResultSet rs) {
        JdbcUtils.closeResultSet(rs);
        JdbcUtils.closeStatement(stmt);
        DataSourceUtils.releaseConnection(con, dataSource);
    }

    private Connection getConnection() throws SQLException {
        Connection con = DataSourceUtils.getConnection(dataSource);
        log.info("get connection={}, class={}", con, con.getClass());
        return con;
    }
}
Connection con = null;
PreparedStatement pstmt = null;

try {
			con = getConnection();
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, memberId);
			pstmt.executeUpdate();
	} catch (SQLException e) {
			throw new MyDbException(e);
	} finally {
		close(con, pstmt, null);
	}

연결 설정 및 해제, 예외 처리를 위한 위의 코드들이 중복됨을 보인다.

이는 JdbcTemplate로 손쉽게 해결 가능

MemberRepositoryV5.class

생성자

private final JdbcTemplate template;

public MemberRepositoryV5(DataSource dataSource) {
    this.template = new JdbcTemplate(dataSource);
}

생성자로 DataSource를 받고, JdbcTemplate에 주입

save()

@Override
public Member save(Member member) {
		String sql = "insert into member(member_id, money) values (?, ?)";
    template.update(sql, member.getMemberId(), member.getMoney());
    return member;
}
  • 반복되는 지저분한 코드를 제거하고 template.update() 메소드를 사용.
  • 파라미터로 sql문법과 member의 정보를 넣어준다.

findById()

@Override
public Member findById(String memberId) {
    String sql = "select * from member where member_id = ?";
    return template.queryForObject(sql, memberRowMapper(), memberId);
}

private RowMapper<Member> memberRowMapper() {
        return (rs, rowNum) -> {
            Member member = new Member();
            member.setMemberId(rs.getString("member_id"));
            member.setMoney(rs.getInt("money"));
            return member;
        };
    }
  • V4의 findById()의 rs = pstmt.executeQuery(); 대신 template.queryForObject()를 사용
  • template.queryForObject(sql, memberRowMapper(), memberId);
    • sql의 결과가 ResultSet으로 memberRowMapper()에 전달되어 람다식을 거친 후 결과로 member가 반환됨.

update()

@Override
public void update(String memberId, int money) {
    String sql = "update member set money=? where member_id=?";
    template.update(sql, money, memberId);
}
  • save()와 동일하게 template.update()를 사용하지만 money와 memberId의 순서의 유의

delete()

@Override
public void delete(String memberId) {
    String sql = "delete from member where member_id = ?";
    template.update(sql, memberId);
}
  • 동일하게 template.update() 사용하지만 파라미터가 다름

 

JdbcTemplate은 Jdbc로 개발할 때 발생하는 '트랜잭션을 위한 커넥션 동기화'는 물론, 예외 발생 시 '스프링 예외 변환기'도 자동으로 실행해준다.