기술 스택
- Spring Boot 3.3.5
- Java 17
- H2 Database
1. 프로젝트 생성
링크 접속 후 H2 Database 설치하자. 스프링 부트 3.X 사용하면 2.1.214 버전 이상을 사용해야 한다고 한다.
설치가 잘 완료되었으면 설치한 폴더에 들어가 cmd를 키고 "h2.bat"라는 명령어를 사용해 H2를 킨다.
그리고 기본 테이블과 더미데이터 삽입.
drop table member if exists cascade;
create table member (
member_id varchar(10),
money integer not null default 0,
primary key (member_id)
);
insert into member(member_id, money) values ('hi1',10000);
insert into member(member_id, money) values ('hi2',20000);
2. JDBC 이해
JDBC 등장이유
애플리케이션을 개발할 때 중요한 데이터는 데이터 베이스에 보관한다.
일반적인 서버와 DB 사용법
1. 커넥션 연결: 주로 TCP/IP를 사용해서 커넥션 연결.
2. SQL 전달: 서버는 DB가 이해할 수 있는 SQL를 연결된 커넥션을 통해 DB에 전달.
3. 결과 응답: DB는 전달된 SQL를 수해앟고 그 결과를 응답.
하지만 문제점이 있다.
각각의 데이터베이스마다 커넥션을 연결하는 방법, SQL을 전달하는 방법, 결과를 응답받는 모든 방법이 모두 다르다는 점이다.
데이터베이스를 다른 종류의 데이터베이스로 변경하면 서버에 개발된 데이터베이스 사용코드도 함께 변경해야 한다.
그리고 개발자들은 커넥션 연결, 응답 받는 방법, SQL 전달까지 새로 학습을 해야 한다.
이런 문제를 해결하기 위해 JDBC라는 자바 표준이 등장한다.
JDBC 표준 인터페이스
- JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접근할 수 있도록 하는 자바 API이다.
대표적으로 JDBC는 3가지 기능을 인터페이스로 제공한다.
- java.sql.Connection: 연결
- java.sql.Statement: SQL을 담은 내용
- java.sql.ResultSet: SQL 요청 응답
개발자는 이 표준 인터페이스만 사용해서 개발하면 된다. 하지만 인터페이스만 있다고 해서 기능이 동작하지 않는다. 이 JDBC 인터페이스를 각각의 DB회사에서 자신의 DB에 맞도록 구현해서 라이브러리로 제공하는데, 이것을 JDBC 드라이버라고 한다.
이렇게 JDBC 등장으로 다른 종류의 데이터베이스로 변경해도 JDBC 구현 라이브러리만 변경하면 된다. 따라서 서버의 사용코드를 그대로 유지할 수 있다.
그리고 개발자는 JDBC 표준 인터페이스 사용법만 학습하면 된다.
※참고
JDBC의 등장으로 많은 것이 편리해졌지만 각각의 데이터베이스마다 SQL, 데이터타입 등의 일부 사용법이 다르기 때문에 만약 데이터베이스가 변경되면 JDBC 코드는 변경하지 않아도 되지만 SQL은 변경해야 한다.
3. JDBC와 최신 데이터 접근 기술
JDBC는 오래된 기술이고 사용방법도 복잡하다. 그래서 최근에는 JDBC를 직접 사용하기 보다는 JDBC를 편리하게 사용하는 다양한 기술이 존재한다. 대표적으로 SQL Mapper와 ORM 기술로 나눌 수 있다.
SQL Mapper
- 장점: JDBC를 편리하게 사용하도록 도와준다
- SQL 응답 결과를 객체로 편리하게 변환
- JDBC의 반복 코드 제거
- 단점: 개발자가 SQL를 직접 작성 해야한다.
- 대표기술: Jdbc Tempalte, MyBatis
ORM 기술
- ORM은 객체를 관계형 데이터베이스 테이블과 매핑해주는 기술.
- 개발자는 반복적인 SQL을 직접 작성하지 않고 ORM 기술이 대신 SQL을 동적으로 생성, 실행
- 각각의 데이터베이스마다 다른 SQL을 사요하는 문제도 중간에서 해결
- 대표기술: JPA, 하이버네이트, 이클립스 링크
- JPA는 자바 진영의 ORM 표준 인터페이스이고, 이것을 구현한 것으로 하이버네이트와 이클립스 링크등의 구현 기술이 있다.
4. 데이터 베이스 연결
이제 애플리케이션과 데이터베이스를 연결해보자. 주의사항으로는 H2 Database를 실행해두자.
ConnectionConst.java
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 = "";
}
데이터베이스 접속하는데 필요한 기본정보를 상수로 만들었다.
이제 JDBC를 사용해서 실제 데이터베이스에 연결하는 코드를 작성해보겠다.
DBConnectionUtil.java
@Slf4j
public class DBConnectionUtil {
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 IllegalArgumentException(e);
}
}
}
데이터베이스에 연결하려면 JDBC가 제공하는 DriverManager.getConnection(..)를 사용하면 된다. 이렇게 하면 스프링이 라이브러리에 있는 데이터베이스 드라이버를 찾아서 해당 드라이버가 제공하는 커넥션을 반환해준다. 이 예시는 H2 데이터 베이스 드라이브가 작동해서 실제 데이터베어스와 커넥션을 맺고 그 결과를 반환해준다.
JDBC DirverManager 연결 이해
JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DC 드라이버들을 관리하고, 커넥션을 획득하는 기능을 제공한다.
5. JDBC 개발 - 등록 (실습)
원래 예제는 등록, 삭제, 수정 기능을 구현했지만 이 글에서는 등록만 진행해보겠다.
Member.java
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;
}
}
MemberRepositoryV0.java
@Slf4j
public class MemberRepositoryVO {
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());
int count = pstmt.executeUpdate();
return member;
}catch (Exception e) {
log.error("db error");
e.printStackTrace();
throw e;
} finally {
close(con, pstmt, null);
}
}
private void close(Connection con, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
}catch (Exception e) {
log.error("error", e);
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
log.error("error", e);
}
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
log.error("error", e);
}
}
}
private Connection getConnection() {
Connection con;
con = DBConnectionUtil.getConnection();
return con;
}
}
커넥션 획득
- getConnection(): 이전에 만들어둔 DBConnectionUtil.java를 통해서 데이터 베이스 커넥션을 획득했다.
SQL 전달 - save()
- sql: 데이터베이스에 전달할 SQL을 정의.
- con.prepareStatement(sql) : 데이터 베이스에 전달할 SQL과 파라미터로 전달할 데이터들을 준비.
- pstmt.setString(1, member.getMemberId()) : SQL의 첫번째 '?' 값에 지정한다.
SQL 실행 - executeUpdate()
- SQL을 실행하는 코드이다. 실행결과에 따라서 성공한 행 갯수만큼 int로 반환한다.
리소스 정리 - close()
- 쿼리를 실행하고 나면 항상 리소스를 정리해야한다. 리소스 정리는 항상 역순으로 진행해야한다.
- 예외가 발생하든 하지 않든 항상 수행되어야 하므로 finally 구문에 주의해서 작성해야 한다. 만약 이 부분을 놓치게 된다면 커넥션이 끊어지지 않고 계속 유지되는 문제가 발생할 수 있다. 이런것을 리소스 누수라고 하는데, 결과적으로 커넥션 부족으로 장애가 발생할 수 있다.
'JDBC' 카테고리의 다른 글
[JDBC] 스프링과 문제 해결 - 예외 처리, 반복 (0) | 2024.11.12 |
---|---|
[JDBC] 자바 예외 이해 (1) | 2024.11.09 |
[JDBC] 트랜잭션 - 스프링과 문제 해결 (3) | 2024.11.08 |
[JDBC] 트랜잭션 이해 (0) | 2024.11.08 |
[JDBC] 커넥션풀과 데이터소스 이해 (0) | 2024.11.07 |