들어가며

  • 저번 포스트에서는 데이터를 저장하는 기능을 JDBC를 사용하여 구현하였다.
  • 이번 포스트에서는 저장된 데이터를 조회하는 기능을 JDBC를 사용하여 구현해본다.

 

 

 

데이터의 조회 구현

  • 데이터를 조회하는 SQL 구문은 다음과 같다.
SELECT * FROM MEMBER WHERE MEMBER_ID=?
  • JDBC를 사용하여 데이터를 조회하기 위해서는 해당 SQL 구문을 DB에 전송할 커넥션이 필요하다.
  • 또한 해당 SQL을 전송시킬 Statement도 필요하다.
  • 그리고 조회한 데이터를 가져올 객체인 ResultSet이라는 객체 역시 필요하다.
public Member findById(String memberId) throws SQLException{

    String sql = "select * from member where member_id=?";

    Connection conn = null;
    PrepareStatement pstmt = null;
    ResultSet rs = null;
    
    try{
        conn = getConnection();
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, memberId);
        
        rs = pstmt.excuteQuery();
        
        if(rs.next()){
            Member member = new Member();
            member.setMemberId(rs.getString("member_id"));
            member.setMoney(rs.getInt("money"));
        } else{
            throw new NoSuchElementException("member not found, memberId = " + memberId);
        }
        
        return member;
    } catch (SQLException e){
        throw e;
    } finally{
        close(conn, pstmt, rs);
    }
}
  • close()와 getConnection()의 경우 이후 전체 코드에서 볼 수 있다. 또는 이전 포스트에서도 볼 수 있다.
  • 이 findById 메서드는 다음과 같은 순서로 동작한다.
    • getConnection()을 통해 커넥션을 연결하고, sql을 전송한다.
    • sql로 인한 연산 결과는 ResultSet이라는 데이터 구조에 저장되는데 ResultSet에서는 Cursor라는 것을 이용하여 그 다음 데이터를 조회할 수 있다.
    • 맨 처음 커서는 아무곳도 가리키고 있지 않기 때문에 rs.next()를 통해 처음 저장된 데이터를 커서가 가리키도록 한 후에 데이터를 조회한다.
      • rs.next() == true 라면 데이터가 존재한다는 의미이다. 반대로 false라면 데이터가 존재하지 않는다는 이야기이다.
    • getTypename("column name")을 통해 해당 컬럼에 존재하는 데이터를 어떤 타입으로 가져올지를 지정할 수 있다. 물론 반환값은 해당 컬럼을 지정 타입으로 변환한 이후의 데이터가 반환된다.
    • memberId와 money를 모두 가져와 멤버 객체에 매핑한다. 만약 이후에 다른 데이터가 존재한다면 rs.next()를 통해 커서를 다음 행으로 옮긴다.
    • 모든 처리가 끝나면 매핑된 맴버 객체를 반환하고 커넥션을 종료한다.

 

 

 

데이터 조회 기능 테스트

  • 구현한 데이터 조회 기능이 잘 동작하는지를 테스트해보자. 이전에 구현한 테스트 클래스를 가져올 것이다.
class MemberRepositoryV0Test{
    MemberRepositoryV0 memberRepository = new MemberRepositoryV0();
    
    @Test
    void crud() throws SQLException{
        Member member = new Member("memberA", 10000);
        repository.save(member);
        
        Member memberA = repository.findById("memberA");
        
        Assertions.assertThat(memberA).isEqualTo(member);
    }
}
  • Assertions는 테스트 결과를 검증하는 도구 클래스이다.
  • assertThat(something1).isEqualTo(something2)은 something1이 something2와 동일한지를 검증할 때 사용한다. 즉 우리가 findById로 찾아온 memberA 객체와 우리가 저장하기 전에 만든 멤버 객체 member가 동일한지를 검증한다.
  • 멤버 클래스를 다시 보도록 하자.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Member{
    private String memberId;
    private int money;
}
  • 아무것도 없는 상태에서 equals 연산을 수행한다면 보통 두 객체의 주소값이 동일한지를 살핀다. 그런데 롬복의 @Data 어노테이션은 내부에 @EqualsAndHashCode 어노테이션이 존재한다.
  • @EqualsAndHashCode 어노테이션은 해당 객체의 해시코드와 두 객체의 값이 동일한지를 판단하는 코드를 자동으로 넣어준다. 따라서 equals을 수행 할 시 memberA와 member의 상태 값(memberId, money)가 동일한지를 판단하는 것으로 변환된다.
  • 따라서 해당 테스트가 성공하게 된다.

 

 

 

정리

  • 지금까지 데이터의 저장, 조회를 구현하였다. 다음 포스트에서는 데이터의 수정을 구현해보고 동일하게 테스팅해본다.
  • 전체적인 코드는 다음과 같다.
public class MemberRepositoryV0{

    public Member save(Member member) throws SQLException{
        String sql = "insert into member(member_id, money) values(?, ?)";
        
        Connection conn = null;
        PreparedStatement pstmt = null;
        
        try{
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            
            pstmt.setString(1, member.getMemberId());
            pstmt.setInt(2, member.getMoney());
            
            pstmt.excuteUpdate();
            
            return member;
        } catch (SQLException e){
            throw e;
        } finally{
            close(conn, pstmt, null);
        }
    }
    
    public Member findById(String memberId) throws SQLException{

        String sql = "select * from member where member_id=?";

        Connection conn = null;
        PrepareStatement pstmt = null;
        ResultSet rs = null;
    
        try{
            conn = getConnection();
            pstmt = conn.prepareStatement(sql);
            
            pstmt.setString(1, memberId);
        
            rs = pstmt.excuteQuery();
        
            if(rs.next()){
                Member member = new Member();
                member.setMemberId(rs.getString("member_id"));
                member.setMoney(rs.getInt("money"));
            } else{
                throw new NoSuchElementException("member not found, memberId = " + memberId);
            }
        
            return member;
        } catch (SQLException e){
            throw e;
        } finally{
            close(conn, pstmt, rs);
        }
    }
    
    public void close(Connection conn, Statement stmt, ResultSet rs){
        if(rs != null){
            try{
                rs.close();
            } catch(SQLException e){
               throw e;
            }
        }
        
        if(stmt != null){
            try{
                stmt.close();
            } catch(SQLException e){
               throw e;
            }
        }
        
        if(conn != null){
            try{
                conn.close();
            } catch(SQLException e){
               throw e;
            }
        }
    }
    
    private Connection getConnection(){
        return DBConnectionUtil.getConnection();
    }

}
복사했습니다!