본문으로 건너뛰기
Advertisement

14.3 R2DBC를 이용한 리액티브 데이터베이스 CRUD

WebFlux 기반의 완전한 논블로킹(Non-blocking) 파이프라인을 구성하려면 데이터베이스 계층도 논블로킹이어야 합니다. **R2DBC(Reactive Relational Database Connectivity)**는 기존 JDBC의 블로킹 특성을 제거한 리액티브 데이터베이스 드라이버 표준입니다.

1. 의존성 및 설정

implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
runtimeOnly 'io.asyncer:r2dbc-mysql:1.2.0' // MySQL R2DBC 드라이버 예시
spring:
r2dbc:
url: r2dbc:mysql://localhost:3306/mydb
username: root
password: secret
경고

R2DBC는 JPA(Hibernate)와 함께 쓸 수 없습니다. 리액티브 스택(WebFlux + R2DBC)과 서블릿 스택(MVC + JPA)은 서로 다른 아키텍처입니다. 하나의 서비스에서 혼용하지 마세요.

2. ReactiveCrudRepository 상속 및 사용

// 1. 엔티티 정의 (@Table로 테이블 매핑, @Id로 기본키)
@Table("users")
@Data
@NoArgsConstructor
public class User {
@Id
private Long id;
private String name;
private String email;
}

// 2. 리액티브 리포지토리 (반환형이 Mono/Flux인 것에 주목)
@Repository
public interface UserR2dbcRepository extends ReactiveCrudRepository<User, Long> {
Flux<User> findByName(String name);
Mono<User> findByEmail(String email);
}

// 3. 서비스 레이어 - 논블로킹 DB 연산
@Service
@RequiredArgsConstructor
public class UserReactiveService {

private final UserR2dbcRepository userRepository;

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

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

public Mono<User> getUserById(Long id) {
return userRepository.findById(id)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다.")));
}

public Mono<Void> deleteUser(Long id) {
return userRepository.findById(id)
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)))
.flatMap(userRepository::delete);
}
}

// 4. WebFlux 컨트롤러 (논블로킹 응답 파이프라인 완성)
@RestController
@RequestMapping("/api/v2/users")
@RequiredArgsConstructor
public class UserReactiveController {
private final UserReactiveService userService;

@GetMapping
public Flux<User> getAll() { return userService.getAllUsers(); }

@GetMapping("/{id}")
public Mono<User> getById(@PathVariable Long id) { return userService.getUserById(id); }

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<User> create(@RequestBody User user) { return userService.createUser(user); }
}

위 코드에서 Controller → Service → Repository 모두 Mono/Flux를 리턴하기 때문에, 요청부터 DB 응답까지 단 하나의 스레드도 블로킹되지 않는 완전한 논블로킹 체인이 완성됩니다.

Advertisement