라티의 작은 일기장

패스트캠퍼스 환급챌린지 3일차 미션 (2월 3일) : 10개 프로젝트로 시작하는 백엔드 웹개발 : 신입 개발자 취업 집중반 강의 후기 본문

Spring(Java)

패스트캠퍼스 환급챌린지 3일차 미션 (2월 3일) : 10개 프로젝트로 시작하는 백엔드 웹개발 : 신입 개발자 취업 집중반 강의 후기

코드라티 2025. 2. 3. 07:01

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

https://bit.ly/4gL1f1o

 

작심삼일을 결정짓는 마지막 날이다!

오늘은 퇴근 후 저녁 약속이 있어 오전에 일찍 일어나서 공부를 시작했다.

오늘 학습한 내용은 JDBC에 관한 것이었다.

 

JDBC는 자바에서 DB에 접근하는 데 사용할 수 있는 인터페이스로, 여기서 접근은 CRUD 작업을 의미하고, DB의 종류는 크게 상관없이 가능하다. (MySQL, Oracle DB, PostgreSQL 등...)

크게 아래 3가지 표준 인터페이스를 제공한다.

- Connection: DB 연결에 사용

- Statement: SQL 전달

- ResultSet: SQL 실행 결과 응답

 

그리고 위 표준 인터페이스는 사용하는 DB에 따라 적합한 인터페이스를 로드해서 사용하게 된다.

 

자바 어플리케이션에서 JDBC API를 사용하는 흐름은 대략 아래와 같다.

JDBC Driver Loading -> Connection -> Statement, PreparedStatement -> executeUpdate(), executeQuery() -> ResultSet, close

조금 더 단순화하면 '드라이버 로드 -> 연결 생성 -> Statement 생성 -> 쿼리 실행 -> 결과 처리 -> 자원 해제' 라고할 수 있을거같다.

 

Connection은 어플리케이션의 관점에서 비용이 많이 드는 작업이다.

왜냐면 DB도 결국 어플리케이션과 분리된 주체이기 때문에, Connection을 맺을 때 네트워크 연결이 필요하고, 어플리케이션이 DB에 접근하기 위한 정보를 기반으로 인증이 끝나야 비로소 생성된 Connection 객체를 어플리케이션에 반환해주기 때문이다.

이걸 DB를 타는 로직을 실행할때마다 반복하는건 너무 큰 비효율이기 때문에, 보통은 Connection Pool이라고 하는 곳에 여러개의 Connection 객체를 미리 생성하고 필요할 때마다 준비되어있는 객체를 사용하는 식으로 비효율을 개선한다.

스프링부트 2.0 이후부터는 Hikari CP를 기본 Connection Pool로서 활용한다고 한다.

(서버 킬 때 Hikari 어쩌구 나오는게 이거인듯)

 

근데 공부하는 입장에서 그냥 한번 생성하고 계속 재사용하면 되는거 아닐까? 하는 생각은 들었는데, 결국 보안 때문에 어쩔 수 없는 선택이었을거같다는 생각이 들었다.

 

추가로 CP는 직접 어플리케이션 단에서 활용하지 않고, 보통 DataSource라고 하는 추상화된 인터페이스를 통해서 활용한다고 한다.

(DataSource를 사용하지 않고 매번 인증정보를 넘겨서 Connection을 생성해서 쓰는 방법도 있긴 했다)

 

그리고 JDBC는 Connection, Statement, ResultSet의 close()를 통한 자원 해제 과정이 필수적이니, 잊지말고 실행해주도록 하자.

추가로 Statement와 PreparedStatement의 차이점이 궁금해서 찾아봤는데, 딱 한번만 실행해야되는 쿼리문이 아니라면 보안, 캐싱 등 성능 관점에서 PreparedStatement를 대부분 활용하는 것 같다.

 

Spring에서는 JDBC를 라이브러리 형태(Spring Data JDBC)로 제공하는데, 나도 얼핏 들어봤던 Spring Data JPA라는 ORM을 활용할 수도 있지만, 기능이 너무 많아서 단순한 프로젝트에서는 굳이 활용하지 않는 것이 좋다고 한다.

 

Spring Data JDBC를 활용하면 JdbcTemplate을 기반으로 DB에 쿼리를 날릴 수 있고, JdbcTemplate은 넘겨받는 DataSource를 기반으로 Connection 생성, DB 쿼리, 결과 반환, 자원 해제를 알아서 다 해주기 때문에 사용하지 않는 경우 대비 코드 가독성이 매우 훌륭해지는 것을 확인할 수 있다.

 

한 가지 예시로 확인해보자.

// JdbcTemplate을 사용하지 않는 경우
public User findUserById(Long userId) {
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    User user = null;
    
    try {
        conn = dataSource.getConnection();
        pstmt = conn.prepareStatement("SELECT id, name, email FROM users WHERE id = ?");
        pstmt.setLong(1, userId);
        rs = pstmt.executeQuery();
        
        if (rs.next()) {
            user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
        }
    } catch (SQLException e) {
        // 예외 처리 로직
        throw new RuntimeException("DB 조회 실패", e);
    } finally {
        // 자원 해제 (실수 가능성 높음)
        try { if (rs != null) rs.close(); } catch (SQLException ignored) {}
        try { if (pstmt != null) pstmt.close(); } catch (SQLException ignored) {}
        try { if (conn != null) conn.close(); } catch (SQLException ignored) {}
    }
    return user;
}

 

// JdbcTemplate을 사용하는 경우
private final JdbcTemplate jdbcTemplate;

public User findUserById(Long userId) {
    return jdbcTemplate.queryForObject(
        "SELECT id, name, email FROM users WHERE id = ?",
        (rs, rowNum) -> {  // 람다를 이용한 RowMapper
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
            return user;
        },
        userId  // 파라미터 자동 바인딩
    );
}

 

추가로 자바 객체의 프로퍼티 명과 DB의 컬럼명이 같다면 이렇게까지 코드를 간소화할 수 있다.

public User findUserById(Long userId) {
    return jdbcTemplate.queryForObject(
        "SELECT * FROM users WHERE id = ?",
        new BeanPropertyRowMapper<>(User.class),
        userId
    );
}

 

코드를 간소화하는게 모든 경우에 있어서 좋지는 않지만(과도한 추상화라던가), 비즈니스 로직 구현에 집중할 수 있게 되어서 복잡한 요구사항을 구현해야하는 경우엔 꼭 코드를 간결하게 관리하도록 하자.

 

 

학습 시작 인증

 

학습 종료 인증

 

첫 번째 클립 수강 인증

 

두 번째 클립 수강 인증

 

학습 인증