Spring Data R2DBC

김기현·2025년 8월 4일

Spring WebFlux

목록 보기
18/28

Spring Data R2DBC는 Spring Data 프로젝트의 일부로 R2DBC 표준을 기반으로 관계형 데이터베이스와의 상호작용을 위한 리액티브 프로그래밍 모델을 제공한다.
기존의 Spring Data JPA나 Spring Data JDBC가 블로킹 방식이었다면, Spring Data R2DBC는 비동기적이고 논블로킹 방식으로 데이터베이스 작업을 처리하여 리액티브 스택과의 완벽한 통합을 목표로 한다.


Spring Data R2DBC의 랙심 특징 및 목적

1. 리액티브 프로그래밍 모델

  • Spring Data R2DBC는 Project Reactor(Mono, Flux)를 사용하여 데이터베이스 쿼리 결과가 Publisher로 반환된다.
  • 이는 데이터가 준비되는 즉시 스트림으로 전달되어 애플리케이션의 응답성과 처리량을 높이는 데 기여한다.

2. 논블로킹 데이터베이스 접근

  • R2DBC 드라이버를 활용하여 데이터베이스 I/O 작업 중에도 애플리케이션 스레드가 블로킹되지 않고 다른 작업을 수행할 수 있도록 한다.
  • 이는 적은 수의 스레드로 더 많은 동시 요청을 처리할 수 있게 하여 리소스 효율성을 극대화 한다.

3. Spring Data Repository 지원

  • Spring Data 프로젝트의 핵심인 Repository추상화를 그대로 활용한다.
  • ReactiveCrudRepository, ReactiveSortingRepository와 같은 인터페이스를 통해 기본적인 CRUD 및 정렬 기능을 리액티브하게 제공한다.
  • 개발자는 인터페이스만 정의하고 Spring Data가 런타임에 구현체를 생성해준다.

4. 자동 쿼리 생성

  • 메소드 이름을 기반으로 쿼리를 자동으로 생성하는 기능을 제공한다.
  • findByLoginId, findById

5. 템플릿 기반 접근

  • R2dbcEntityTemplate을 제공하여 저수준의 R2DBC API를 직접 다룰 필요 없이 SQL 쿼리를 실행하거나 엔티티를 매핑하는 데 사용할 수 있다.

6. 경량 ORM 기능

  • 완전한 ORM(Object-Relational Mapping) 솔루션인 JPA와 다르게, Spring Data R2DBC는 더 가볍고 단순한 매핑 기능을 제공한다.
  • 복잡한 지연 로딩이나 캐싱 기능은 포함하지 않으며 주로 1:1, 1:N 관계 매핑보다는 단일 엔티티 CRUD에 초점을 맞춘다.

7. 다양한 RDBMS 지원

  • R2DBC 드라이버가 제공되는 다양한 관계형 데이터베이스를 지원한다.
    • ex: MySQL, ProstgreSQL, SQL Server, H2 등

Spring Data R2DBC 사용의 장점

  • 진짜 리액티브 스택: Spring WebFlux 같은 리액티브 웹 프레임워크와 함께 사용될 때, 데이터베이스 레이어까지 논블로킹으로 유지하여 엔드-투-엔드 리액티브 애플리케이션을 구축할 수 있다.
  • 향상된 확장성: 높은 동시성 환경에서 저은 스레드로 많은 요청을 처리할 수 있어 시스템의 확장성과 처리량이 향상된다.
  • 리소스 효율성: 스레드 블로킹이 없어 서버 리소스(CPU, 메모리) 사용을 최적화할 수 있다.
  • 간결한 데이터 접근 코드: Spring Data Repository를 통해 보일플레이트 코드를 줄이고 비즈니스 로직에 집중할 수 있도록 돕는다.

Spring Data R2DBC 사용 시 고려사항

  • 반응형 프로그래밍 지식: Mono, Flux 등의 반응형 타입과 subscribe(), map(), flatMap() 등의 연산자에 대한 이해가 필수적이다.
  • ORM 기능 제한: JPA와 같은 ORM의 풍부한 기능(ex: 영속성 컨텍스트, 지연 로딩, 캐싱, 복잡한 연관관계 매핑)을 기대한다면 Spring R2DBC는 적합하지 않을 수 있다. Spring Data R2DBC는 더 명시적이고 제어 가능한 데이터베이스 접근을 선호하는 경우에 유리하다.
  • 트랜잭션 관리: 리액티브 환경에서 트랜잭션 관리는 블로킹 방식과 다소 차이가 있다. @Transactional 애노테이션은 사용할 수 있지만, TransactionalOperator와 같은 리액티브 트랜잭션 API를 이해하는 것이 좋다.
  • SQL 중심: JPA에 비해 더 SQL에 가깝게 접근한다. 물론 Repository 추상화를 통해 SQL을 직접 작성할 필요는 줄어들지만 복잡한 쿼리나 특정 데이터베이스 기능 활용 시에는 R2dbcEntityTemplate를 사용하여 직접 SQL을 작성해야 할 수도 있다.

예시

// 1. 엔티티 정의
@Data // Lombok
@Table("users") // 데이터베이스 테이블 매핑
public class User {
  @Id // 기본 키
  private Long id;
  private String loginId;
  private String password;
  private int age;
}

// 2. 리포지토리 인터페이스 정의
public interface UserRepository extends ReactiveCrudRepository<User, Long> {
  // 메서드 이름으로 쿼리 자동 생성 (예: SELECT * FROM users WHERE first_name = ? AND last_name = ?)
  Flux<User> findByLoginId(String loginId);

  // 나이가 특정 값보다 큰 사용자 찾기
  Flux<User> findByAgeGreaterThan(int age);
}

// 3. 서비스 계층에서 사용
@Service
public class UserService {
  private final UserRepository userRepository;

  public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  public Flux<User> findAllUsers() {
    return userRepository.findAll();
  }

  public Mono<User> findUserById(Long id) {
    return userRepository.findById(id);
  }

  public Mono<User> saveUser(User user) {
    return userRepository.save(user);
  }

  public Mono<Void> deleteUserById(Long id) {
    return userRepository.deleteById(id);
  }

  public Flux<User> findUserByLoginId(String loginId) {
    return userRepository.findByLoginId(loginId);
  }
}
profile
백엔드 개발자를 목표로 공부하는 대학생

0개의 댓글