[Spring DB] 1.JDBC
Updated:
JDBC
Client가 데이터를 저장하는 작업을 수행할 때 앱이나 웹에서 Application Server을 거쳐 DB에 접근한다. 이 과정에서 Application Server와 DB 사이의 연결에 대해 알아보자
배경지식
Application Server와 DB 간의 통신

- 커넥션 연결: 대부분 TCP/IP를 이용하여 연결
- SQL 전달: Application Server 측에서 작성한 SQL을 DB로 전달
- 결과 응답: DB 측에서 SQL을 실행한 결과를 Application Server로 전달
1. JDBC
과거에는 위 3가지 과정을 각각의 DB마다 다른 방식으로 수행했기 때문에 DB가 변경되면 Application Server의 코드들도 변경할 수 밖에 없었다…
이 문제를 해결하기 위해 등장한 것이 JDBC 표준 인터페이스이다. Java Database Connectivity로 Java에서 DB에 접속할 수 있도록 도와주는 API이다

JDBC 표준 인터페이스는 하위 3가지 기능을 정의한다
java.sql.Connection: 커넥션 연결을 담당java.sql.Statement: SQL을 담고있음java.sql.ResultSet: SQL 요청에 대한 응답을 담고있음
=> JDBC 표준 인터페이스를 MySQL, Oracle 등 각각의 DB에 맞게 구현한 것을 JDBC 드라이버라고 부른다. Application 로직은 JDBC 표준 인터페이스(추상화)에 의존하기 때문에 다른 종류의 DB를 사용하고 싶다면 JDBC 드라이버만 바꿔주면 된다
2. 최신 데이터 접근 기술: SQL Mapper, ORM
최근에는 JDBC를 직접 사용하기 보다는 JDBC를 편리하게 사용할 수 있도록 도와주는 SQL Mapper와 ORM을 사용한다. 이 2가지 각각의 기술을 통해 손쉽게 SQL을 JDBC로 전달한다
2-1. SQL Mapper

- SQL 응답 결과를 객체로 편리하게 변환해주고 JDBC의 반복코드를 줄여준다는 장점
- 개발자가 SQL을 직접 작성해야하는 단점
- eg) JdbcTemplate, MyBatis
2-2. ORM

- 객체를 RDB의 테이블과 매핑해주는 기술로 개발자가 직접 SQL을 작성할 필요가 없이 JPA가 사용하는 DB에 따라 SQL문을 작성하여 실행한다
- Java 진영 ORM 표준 인터페이스가 JPA이고 대부분 이를 구현한 라이브러리로 Hibernate를 사용한다
- eg) JPA
3. 순수 JDBC 개발하기
3-1. Connection 연결
Connection connection = DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test", "sa", "");

- Application 로직에서 DB와 연결이 필요하다면
DriverManager.getConnection()을 호출한다 - DriverManager는 라이브러리로 등록된 드라이버 목록 모두에게 연결 요청한다
DriverManager.getConnection()의 url 파라미터 값을 통해 사용할 수 있는 드라이버가 결정된다- url 파라미터 값 앞부분이
jdbc:h2이면 H2 드라이버를 사용하는 식이다
- 해당 연결을 처리할 수 있는 드라이버는 connection을 Application 로직에 반환한다
3-2. Statement에 SQL 담아 ResultSet으로 응답받기
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("jdbc:h2:tcp://localhost/~/test", "sa", "");
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("No Member for Id:" + memberId);
}
} catch (SQLException e) {
log.error("DB error", e);
throw e;
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
log.info("error", e);
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
log.info("error", e);
}
}
}
}
- SQL을 담기 위한 Statement로
PreparedStatement를 사용한다 - DB에서 해당 SQL을 실행한 결과를 담는
ResultSet을 사용한다ResultSet의 최초 커서는 데이터를 가르키고 있지 않으므로rs.next()를 적어도 최초 한번 호출해야 한다rs.next()의 반환값이true이면 데이터가 있다는 뜻이고,false이면 없다는 뜻이다- 반환값을 여러개로 예상하는 경우에는
while(rs.next())를 이용한다
- finally문에서
Connection,Statement,ResultSet을 종료시킬때 에러가 발생해도 서로에게 영향을 주지 않도록 로직을 작성한다
Leave a comment