JDBC를 사용해서 회원 Member 데이터를 데이터베이스에 관리하는 기능을 개발해보자
H2 데이터베이스 설정 마지막에 있는 테이블과 샘플 데이터 만들기를 통해 member 테이블을 미리 만들어 둔다.
schema.sql
drop table member if exists cascade;
create table member (
member_id varchar(10),
money integer not null default 0,
primary key (member_id)
);
domain 패키지를 만들고
Member class를 만들어준다.
package hello.jdbc.domain;
import lombok.Data;
@Data
public class Member {
private String memberId;
private int money;
public Member() {
}
public Member(String memberId, int money) {
this.memberId = memberId;
this.money = money;
}
}
repository package도 만들고 MemberRepositoryV0 클래스를 만들어준다.
package hello.jdbc.repository;
import hello.jdbc.connection.DBConnectionUtil;
import hello.jdbc.domain.Member;
import lombok.extern.slf4j.Slf4j;
import java.sql.*;
/**
* JDBC - DriverManager 사용
*/
@Slf4j
public class MemberRepositoryV0 {
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());
return member;
} catch (SQLException e) {
log.error("db error", e);
throw e;
} finally {
close(con, pstmt, null);
}
}
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();
}
}
- 리소스 정리
쿼리 실행하면 리소스를 정리해야 함. 여기서는 Connection / PreparedStatement를 사용했다. 리소스를 정리할 때 항상 역순으로 해야한다. Connection을 먼저 획득하고 Connection을 통해 PreparedStatement를 만들었기 때문에 리소스를 반환할 때 PreparedStatement를 먼저 종료하고, 그 다음에 Connection을 종료하면 된다.
여기서 사용하지 않은 ResultSet은 결과를 조회할 때 사용한다. 조회 부분에서 다루어 본다.
- 주의사항
리소스 정리는 꼭 ! 해주어야 한다. 예외가 발생하든, 하지 않든 항상 수행되어야 하므로 finally 구문에 주의해서 작성해야 하고 만약 이 부분을 놓치면 커넥션이 끊어지지 않고 계속 유지되는 문제가 발생한다. 리소스 누수라고 하는데 결과적으로 커넥션 부족으로 장애가 발생할 수 있다.
- 참고
PreparedStatement는 Statement의 자식 타입이고, ?를 통한 파라미터 바인딩을 가능하게 해준다. 참고로 SQL Injection 공격을 예방하려면 PreparedStatement를 통한 파라미터 바인딩 방식을 사용해야 한다.
MemberRepositoryV0의 Test 케이스도 만들어준다.
// MemberRepositoryV0Test
package hello.jdbc.repository;
import hello.jdbc.domain.Member;
import org.junit.jupiter.api.Test;
import java.sql.SQLException;
import static org.junit.jupiter.api.Assertions.*;
class MemberRepositoryV0Test {
MemberRepositoryV0 repository = new MemberRepositoryV0();
@Test
void crud() throws SQLException {
Member member = new Member("memberV0", 10000);
repository.save(member);
}
}
실행하면 결과가 h2DB의 member 테이블에 반영이 된다. 같은 값으로 테스트를 실행하면 에러가 나므로 다른 값으로 넣어서 실행도 해보자.
@Test
void crud() throws SQLException {
Member member = new Member("memberV1", 10000);
repository.save(member);
}
}
<출처 김영한: 스프링 DB 1편 - 데이터 접근 핵심 원리>
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard
스프링 DB 1편 - 데이터 접근 핵심 원리 - 인프런 | 강의
백엔드 개발에 필요한 DB 데이터 접근 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 DB 접근 기술의 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., - 강의
www.inflearn.com
'Spring > SpringDB' 카테고리의 다른 글
DataSource 예제2 - 커넥션 풀 (0) | 2022.06.14 |
---|---|
DataSource 예제 - DriverManager (0) | 2022.06.14 |
DataSource 이해 (0) | 2022.06.14 |
커넥션 풀 이해 (0) | 2022.06.14 |
JDBC 개발 - 조회 / 수정, 삭제 (0) | 2022.06.14 |