이번에는 JDBC를 통해 이전에 저장한 데이터를 조회하는 기능을 개발해봅시다.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.NoSuchElementException;
/**
* JDBC - DriverManager 사용
*/
@Slf4j
public class MemberRepositoryV0 {
public Member findById(String memberId) throws SQLException {
//...1
String sql = "select * from member where member_id = ?";
Connection con = null;
PreparedStatement pstmt = null;
//...3
ResultSet rs = null;
try {
con = getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, memberId);
//...2
rs = pstmt.executeQuery();
if (rs.next()) { //...4, 9
Member member = new Member();
//...5
member.setMemberId(rs.getString("member_id"));
//...6
member.setMoney(rs.getInt("money"));
return member;
} else {
//...7
throw new NoSuchElementException("member not found memberId=" + memberId);
}
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, rs);
}
}
private void close(Connection con, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
log.info("error", e);
}
}
}
private Connection getConnection() {
return DBConnectionUtil.getConnection();
}
}
데이터 조회를 위한 select SQL을 준비합니다.
executeQuery()
ResultSet executeQuery() throws SQLException;
ResultSet
보통 select 쿼리의 결과가 순서대로 들어갑니다.
예를 들어서 select member_id, money
라고 지정하면 member_id , money 라는 이름으로 데이터가 저장됩니다.
참고로 select *
을 사용하면 테이블의 모든 컬럼을 다 지정합니다.
ResultSet 내부에 있는 커서( cursor )를 이동해서 다음 데이터를 조회할 수 있습니다.
→ 예시 자세히
rs.next()
이것을 호출하면 커서가 다음으로 이동합니다.
참고로 최초의 커서는 데이터를 가리키고 있지 않기 때문에 rs.next() 를 최초 한번은 호출해야 데이터를 조회할 수 있습니다.
rs.next() 의 결과가 true 면 커서의 이동 결과 데이터가 있다는 뜻입니다.
rs.next() 의 결과가 false 면 더이상 커서가 가리키는 데이터가 없다는 뜻입니다.
rs.getString("member_id") 는 현재 커서가 가리키고 있는 위치의 member_id 데이터를 String 타입으로 반환합니다.
rs.getInt("money") 는 현재 커서가 가리키고 있는 위치의 money 데이터를 int 타입으로 반환합니다.
예외 메시지는 잘 정리하는 게 좋습니다. 특히 id같은 유니크 키 값은 넣어두는게 좋습니다. 그래야 문제가 생겼을 때 어떤 member에서 문제가 생겼는지 파악하기 수월합니다.
리소스 정리는 사용한 순서 반대로 해야합니다.
그니까 해제할 때는 ResultSet, PrepareStatement, Connection 순서대로 해제하면 됩니다.
지금까지 만든 findById() 에서는 회원 하나를 조회하는 것이 목적입니다.
따라서 조회 결과가 항상 1건이므로 while 대신에 if를 사용했습니다.
SQL을 보면 PK인 member_id 를 항상 지정하는 것을 확인할 수 있죠.
참고로 이 ResultSet 의 결과 예시는 회원이 2명 조회되는 경우입니다.