애플리케이션 서버가 DB를 사용하는 방법
❗️ 문제 상황
각 DB마다 커넥션 연결하는 법, SQL 전달하는 법, 결과 응답받는 법이 전부 다르다.
(1) DB 종류를 변경하는 경우, 애플리케이션 코드(DB 사용 코드)를 변경해야 한다.
(2) 개발자가 각 DB마다 커넥션 연결, SQL 전달, 응답받는 방법을 새로 학습해야 한다.
✔️ 해결
JDBC(Java DB Connectivity) 도입
java.sql.Connection
java.sql.Statement
java.sql.ResultSet
개발자는 이 인터페이스를 사용해서 애플리케이션을 개발하면 된다.
👨🏻💻 정리
문제1. DB 종류를 변경하는 경우, 애플리케이션 코드(DB 사용 코드)도 수정해야 한다.
-> 애플리케이션은 이제 JDBC에만 의존하기 때문에, DB 종류를 변경하더라도 애플리케이션 코드는 수정할 필요가 없다. JDBC 드라이버만 변경하면 된다.
문제2. 개발자는 DB 종류에 따라 커넥션 연결, SQL 전달, 결과 응답받는 방법을 새로 학습해야 한다.
-> 개발자는 JDBC 사용법만 학습하면 된다.
JDBC의 한계: 각 DB마다 데이터 타입(EX. MySQL의 varchar, Oracle의 varchar2), SQL(EX. 페이징 처리) 등 일부 사용법이 다르다. ANSI SQL(= 표준 SQL)이 존재하기는 하지만 일반적인 부분만 공통화했기 때문에 한계가 있다. 결국, DB 종류를 변경하면 SQL을 해당 DB에 맞도록 변경해야 한다.
JDBC를 직접 사용하기 보다는 JDBC를 편리하게 사용하는 다양한 기술 존재
※ 이러한 기술들도 내부적으로는 JDBC를 사용한다. 따라서 JDBC를 직접 사용하지 않더라도, JDBC의 내부 동작 원리는 반드시 알고 있어야 한다.
public Member save(Member member) throws SQLException {
String sql = "insert into member(member_id, money) values(?, ?)";
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
pstmt = conn.prepareStatement(sql); //SQLException
pstmt.setString(1, member.getMemberId());
pstmt.setInt(2, member.getMoney());
pstmt.executeUpdate();
return member;
} catch (SQLException e) {
log.info("error", e);
throw e;
} finally {
close(conn, pstmt, null);
}
}
private void close(Connection conn, Statement stmt, ResultSet rs) throws SQLException {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.info("error", e);
throw e;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.info("error", e);
throw e;
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("error", e);
throw e;
}
}
}
Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
적절한 JDBC 드라이버 찾는 과정
String sql = "insert into member(member_id, money) values(?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, member.getMemberId());
pstmt.setInt(2, member.getMoney());
pstmt.executeUpdate();
pstmt.close();
conn.close();
public Member findById(String memberId) throws SQLException {
String sql = "select * from member where member_id = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
pstmt = conn.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) {
log.info("error", e);
throw e;
} finally {
close(conn, pstmt, rs);
}
}
DB 데이터 변경(= insert, delete, update)할 때는 executeUpdate(), 조회할 때는 executeQuery()를 사용한다. executeQuery()는 select의 결과를 ResultSet에 담아서 반환한다.
ResultSet의 구조
close() 메소드를 다음과 같이 수정하자.
private void close(Connection conn, Statement stmt, ResultSet rs) throws SQLException {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(stmt);
JdbcUtils.closeConnection(conn);
}
JdbcUtils를 사용하기 위해서는 spring-boot-starter-jdbc 라이브러리를 추가해야 한다.
implementation 'org.springframework.boot:spring-boot-starter-jdbc'