JDBC란?
JDBC의 정의는 다음과 같다.
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다. JDBC 는 데이터베이스에서 자료를 쿼리하거나 업데이트하는 방법을 제공한다. [출처: 위키백과]
정리하자면 자바에서 데이터베이스에 접속할 수 있게 해주는 기술이다.
우리는 어플리케이션을 개발할 때 데이터를 데이터베이스에 저장한다.
어플리케이션에서 데이터베이스에 접근해 데이터를 저장하고 가져오려면 다음의 세가지 기능이 필요하다.
- 커넥션 연결
- SQL 전달
- 결과 응답
하지만 이러한 과정을 구현하는 방식은 데이터베이스 시스템마다 다르다.
MySQL만의 방식이 있을 것이고 Oracle 만의 방식이 있을 것이다.
이러면 연결하는 데이터베이스마다 새롭게 코드를 작성해서 데이터베이스를 연결해야하는 귀찮음이 발생한다.
JDBC는 이러한 상황을 해결해준다.
- 커넥션 연결 -- java.sql.Connection
- SQL 전달 -- java.sql.Statement
- 결과 응답 -- java.sql.ResultSet
JDBC는 이 세가지 기능을 자바 표준 인터페이스로 만들어 어떠한 데이터베이스를 사용해도 개발자는 간편하게 데이터베이스에 접근할 수 있게 해준다.
코드로 알아보기
Connection
먼저 데이터베이스와 커넥션을 연결하는 부분이다.
커넥션을 연결하기 위해서는 데이터베이스에 대한 기본 설정정보가 필요하다. 크게 세 가지가 필요하다.
- url
- username
- password
public abstract class ConnectionConst {
public static final String URL = "jdbc:h2:tcp://localhost/~/test";
public static final String USERNAME = "sa";
public static final String PASSWORD = "";
}
여기서는 h2 데이터베이스를 사용했다.
public static Connection getConnection() {
try {
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
log.info("get connection={}, class={}", connection, connection.getClass());
return connection;
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
DriverManager.getConnection(...): 데이터베이스의 기본설정 정보를 넣어주게 되면 데이터베이스 커넥션을 반환한다.
애플리케이션은 그냥 커넥션 요청만 하면 알아서 JDBC가 알아서 내 데이터베이스를 보고 연결시켜준 뒤 커넥션을 반환해준다. 반환 받은 커넥션을 가지고 데이터베이스에 마음대로 접근하면 된다.
Statement & ResultSet
CRUD SQL을 날리고(Statement) 이에 대한 결과를 받는(ResultSet) 부분이다.
이 과정은 크게 4가지로 나눌 수 있다.
1. Connection 가져오기
Connection con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
2. Statement 가져와 sql 실행하기
pstmt = con.prepareStatement(sql);
pstmt.executeUpdate(); // insert, update, delete의 경우
pstmt.executeQuery(); // select의 경우
3. 받아올 결과가 있으면 ResultSet으로 결과 받아오기
(select문의 경우에 해당한다.)
rs = pstmt.executeQuery();
4. 사용한 Connection, Statement, ResultSet을 닫아주기
💡반드시 연순의 반대로 닫아야 한다.
[연 순서: Connection - Statement - ResultSet]
[닫는 순서: ResulSet - Statement - ResultSet]
rs.close(); // ResultSet
stmt.close(); // Statement
con.close(); // Connection
예시코드를 위한 시나리오
- 회원 데이터를 데이터베이스에 관리하는 기능
- 회원 테이블은 다음과 같다.
- 리포지토리 로직
- 회원을 데이터베이스에 저장한다. (INSERT)
- member_id를 통해 회원 정보를 찾아온다. (SELECT)
- 특정 회원의 money를 업데이트 한다. (UPDATE)
- 특정 회원을 삭제한다. (DELETE)
예시코드
1. 회원을 데이터베이스에 저장한다. (INSERT)
public Member save(Member member) throws SQLException {
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) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
1) Connection 가져오기
con = getConnection();
2) State를 가져와 SQL 실행하기
String sql = "insert into member(member_id, money) values(?, ?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getMemberId());
pstmt.setInt(2, member.getMoney());
pstmt.executeUpdate();
데이터베이스를 업데이트 하는 경우 executeUpdate()
3) 받아올 결과가 있으면 ResultSet으로 결과 받아오기
이 경우 데이터를 삽입하는 것이므로 받아올 결과가 따로 없어 이 부분은 생략해도 된다.
4) 사용한 Connection, Statement, ResultSet을 닫아주기
close(con, pstmt, null);
close() 메서드:
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);
}
}
}
여기서 주의해야할 점은 ResultSet --> Statement --> Connection 순으로 닫아야 한다.
즉, 열었을 때와 반대 순서로 닫아야 한다.
2. member_id를 통해 회원 정보를 찾아온다. (SELECT)
public Member findById(String memberId) throws SQLException {
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) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, rs);
}
}
여기서 다른 점은 딱 한가지이다.
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);
}
select문이기 때문에 ResultSet이 존재한다.
3. 특정 회원의 money를 업데이트 한다. (UPDATE)
public void update(String memberId, int money) throws SQLException {
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) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
4. 특정 회원을 삭제한다. (DELETE)
public void delete(String memberId) throws SQLException {
String sql = "delete from member where member_id=?";
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, memberId);
pstmt.executeUpdate();
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
출처: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard
'Spring > Spring Data' 카테고리의 다른 글
[Spring Data] SQL Mapper VS ORM (0) | 2024.06.05 |
---|---|
[Spring Data] 예외로 인한 의존성과 스프링의 예외 추상화 (0) | 2024.04.30 |
[Spring Data] Spring Transaction을 통한 문제해결 (0) | 2024.04.29 |
[Spring Data] JDBC 트랜잭션 (0) | 2024.04.29 |
[Spring Data] 커넥션 풀과 데이터 소스 (0) | 2024.04.29 |