Files
spring-boot-examples/docs/35_jdbc_client.md
2025-04-08 19:56:24 +09:00

10 KiB

Spring JDBC Client 소개 및 활용

Spring 6부터 도입된 **JdbcClient**는 기존 JdbcTemplate보다 더 간결하고 현대적인 API를 제공합니다.
특히, 메서드 체이닝과 함수형 스타일의 코드 작성이 가능하여, 기존 JDBC 코드보다 훨씬 직관적인 사용이 가능합니다.

이 글에서는 JdbcClient의 주요 기능과 사용법을 예제와 함께 설명하겠습니다.


1. JdbcClient란?

JdbcClientSpring 6 및 Spring Boot 3에서 새롭게 추가된 기능으로,
기존 JdbcTemplate이 가진 장점은 유지하면서도, 코드의 가독성과 유지보수성을 개선한 API입니다.

✔ 기존 JdbcTemplate보일러플레이트 코드가 많음
JdbcClient메서드 체이닝을 지원하여 코드가 간결해짐
SQL 실행 및 데이터 조회를 직관적으로 처리 가능


2. JdbcClient 사용법

📌 2.1 의존성 추가

Spring Boot 3 이상에서는 자동으로 포함되므로 별도 의존성 추가는 필요 없습니다.
하지만, Spring Framework 6에서 단독으로 사용할 경우 다음과 같은 의존성이 필요합니다.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>6.x.x</version>
</dependency>

📌 2.2 JdbcClient 빈 설정

JdbcClientDataSource를 기반으로 생성됩니다.

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DatabaseConfig {

    @Bean
    public JdbcClient jdbcClient(DataSource dataSource) {
        return JdbcClient.create(dataSource);
    }
}

JdbcClient.create(dataSource) 를 사용하여 인스턴스 생성
Spring Boot 환경에서는 자동 설정되므로 따로 등록할 필요 없음


3. CRUD 예제

📌 3.1 데이터 삽입 (INSERT)

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public int insertUser(String name, String email) {
        return jdbcClient.sql("INSERT INTO users (name, email) VALUES (:name, :email)")
                .param("name", name)
                .param("email", email)
                .update();
    }
}

sql("INSERT INTO users ...")SQL 작성
param("name", name)이름 기반 파라미터 바인딩
update()INSERT/UPDATE/DELETE 실행


📌 3.2 단일 데이터 조회 (SELECT - 단건 검색)

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public Optional<User> findById(Long id) {
        return jdbcClient.sql("SELECT * FROM users WHERE id = :id")
                .param("id", id)
                .query(User.class)
                .optional();
    }
}

query(User.class)자동으로 User 객체로 매핑
optional()결과가 없을 경우 Optional.empty() 반환


📌 3.3 여러 데이터 조회 (SELECT - 리스트 검색)

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public List<User> findAll() {
        return jdbcClient.sql("SELECT * FROM users")
                .query(User.class)
                .list();
    }
}

query(User.class).list()리스트 형태로 결과 반환


📌 3.4 데이터 업데이트 (UPDATE)

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public int updateEmail(Long id, String email) {
        return jdbcClient.sql("UPDATE users SET email = :email WHERE id = :id")
                .param("email", email)
                .param("id", id)
                .update();
    }
}

update()를 사용하여 데이터를 수정


📌 3.5 데이터 삭제 (DELETE)

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public int deleteById(Long id) {
        return jdbcClient.sql("DELETE FROM users WHERE id = :id")
                .param("id", id)
                .update();
    }
}

update()를 사용하여 DELETE 실행


4. RowMapper 없이 자동 매핑하기

기존 JdbcTemplate에서는 RowMapper를 사용하여 수동으로 매핑해야 했지만,
JdbcClient자동으로 Java 객체와 매핑할 수 있습니다.

import org.springframework.jdbc.core.simple.JdbcClient;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class UserRepository {

    private final JdbcClient jdbcClient;

    public UserRepository(JdbcClient jdbcClient) {
        this.jdbcClient = jdbcClient;
    }

    public List<User> findAll() {
        return jdbcClient.sql("SELECT * FROM users")
                .query(User.class)
                .list();
    }
}

User 객체의 필드명과 DB 컬럼명이 일치하면 자동 매핑


5. 정리

기능 JdbcTemplate JdbcClient
SQL 실행 방식 jdbcTemplate.query(sql, rowMapper) jdbcClient.sql(sql).query(clazz)
파라미터 바인딩 new MapSqlParameterSource() 사용 .param("name", value) 사용
결과 변환 RowMapper 필요 자동 매핑 가능
코드 스타일 절차 지향 함수형 스타일
가독성 비교적 복잡 간결하고 직관적

JdbcClientSpring Boot 3 이상에서 사용 가능
✔ 기존 JdbcTemplate 대비 더 간결하고 직관적인 코드 작성 가능
자동 매핑 기능 제공하여 RowMapper 작성 불필요

Spring Boot 3 이상을 사용한다면, JdbcTemplate 대신 더 강력하고 간결한 JdbcClient를 활용하는 것이 추천됩니다! 🚀


Spring JdbcClient 주요 메서드 정리

Spring 6 및 Spring Boot 3에서 도입된 JdbcClient기존 JdbcTemplate보다 간결한 API를 제공합니다.
아래는 JdbcClient의 주요 메서드를 설명과 함께 표로 정리한 것입니다.


1. JdbcClient 주요 메서드 정리

메서드 설명 예제
sql(String sql) 실행할 SQL을 설정 jdbcClient.sql("SELECT * FROM users")
param(String name, Object value) 이름 기반 파라미터 바인딩 .param("id", 1L)
paramSource(SqlParameterSource params) Map 또는 Bean을 파라미터로 전달 .paramSource(new MapSqlParameterSource(Map.of("id", 1L)))
query(Class<T> clazz) 결과를 자동 매핑하여 반환 .query(User.class).list()
query(RowMapper<T> rowMapper) 커스텀 RowMapper를 사용한 쿼리 실행 .query((rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name"))).list()
queryForObject(Class<T> clazz) 단일 결과 반환 (Optional<T> 지원) .queryForObject(User.class).optional()
list() 여러 개의 결과를 리스트로 반환 .query(User.class).list()
optional() 단일 결과를 Optional로 반환 .queryForObject(User.class).optional()
update() INSERT, UPDATE, DELETE 실행 .sql("UPDATE users SET name = :name WHERE id = :id").update()
execute(Function<Connection, T> callback) JDBC 커넥션을 직접 다룰 때 사용 .execute(conn -> conn.prepareStatement("DELETE FROM users").executeUpdate())

2. JdbcClient 주요 메서드 예제

📌 단일 데이터 조회 (queryForObject)

Optional<User> user = jdbcClient.sql("SELECT * FROM users WHERE id = :id")
    .param("id", 1L)
    .queryForObject(User.class)
    .optional();

SQL 실행 후 User.class로 자동 매핑
✔ 결과가 없을 경우 Optional.empty() 반환


📌 여러 데이터 조회 (query + list)

List<User> users = jdbcClient.sql("SELECT * FROM users")
    .query(User.class)
    .list();

User.class 타입으로 리스트 변환


📌 데이터 삽입 (update)

int rows = jdbcClient.sql("INSERT INTO users (name, email) VALUES (:name, :email)")
    .param("name", "Alice")
    .param("email", "alice@example.com")
    .update();

update()를 실행하여 INSERT 수행
✔ 반영된 행 수(int) 반환


📌 데이터 삭제 (update)

int rowsDeleted = jdbcClient.sql("DELETE FROM users WHERE id = :id")
    .param("id", 1L)
    .update();

✔ 삭제된 행 수 반환


📌 수동 매핑 (RowMapper 사용)

List<User> users = jdbcClient.sql("SELECT * FROM users")
    .query((rs, rowNum) -> new User(rs.getLong("id"), rs.getString("name")))
    .list();

RowMapper를 직접 정의하여 결과 매핑 가능


3. 정리

  • JdbcClient는 기존 JdbcTemplate보다 간결하고 현대적인 API 제공
  • 메서드 체이닝 지원으로 코드 가독성이 향상됨
  • queryForObject(), query()를 활용하면 자동 매핑 가능
  • update()를 사용하여 INSERT, UPDATE, DELETE 실행

Spring Boot 3 이상을 사용한다면 JdbcTemplate보다 JdbcClient를 적극 활용하는 것이 추천됩니다! 🚀