0Pricing
Spring Boot 4 Complete Guide · 강의

리액티브 데이터 접근 및 통합

WebFlux 애플리케이션을 리액티브 데이터 저장소에 연결하고 다른 리액티브 구성 요소와 통합합니다.

리액티브 데이터 접근 및 통합은(는) CoddyKit의 무료 Spring Boot 4 Complete Guide 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Spring Boot 4 Complete Guide 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Spring Boot 4 Complete Guide 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Reactive Data Access Needs

When building reactive applications with Spring WebFlux, traditional data access methods like Spring Data JPA or plain JDBC won't work. Why?

These methods are blocking. They pause the application thread while waiting for database operations to complete. This goes against the non-blocking, asynchronous nature of reactive programming.

Introducing Reactive Data Stores

To maintain the reactive flow, we need reactive data stores and drivers that support non-blocking I/O. These drivers return Mono or Flux, allowing your application to do other work while the database processes requests.

Common reactive databases include:

  • MongoDB: A NoSQL document database.
  • Cassandra: A NoSQL wide-column store.
  • Redis: A NoSQL key-value store, often used for caching.
  • R2DBC: (Reactive Relational Database Connectivity) for relational databases like PostgreSQL, MySQL, H2.

Setting Up Reactive MongoDB

For our examples, we'll focus on MongoDB, a popular choice for reactive applications. First, you need the right dependency in your pom.xml (Maven) or build.gradle (Gradle):

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId> </dependency>

This starter brings in Spring Data MongoDB Reactive, allowing you to easily interact with MongoDB in a non-blocking way.

Defining Reactive Entities

Just like with traditional Spring Data, you define entities that map to your database collections. For MongoDB, you use the @Document annotation.

The @Id annotation marks the primary key field. This tells Spring Data how to identify unique documents.

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "products")
public class Product {
  @Id
  private String id;
  private String name;
  private double price;

  public Product(String id, String name, double price) {
    this.id = id;
    this.name = name;
    this.price = price;
  }

  // Getters and Setters (omitted for brevity)
  public String getId() { return id; }
  public String getName() { return name; }
  public double getPrice() { return price; }

  @Override
  public String toString() {
    return "Product{id='" + id + "', name='" + name + "'}";
  }
}

Creating Reactive Repositories

To perform CRUD operations (Create, Read, Update, Delete) on your entities, you create repository interfaces. For reactive MongoDB, you extend ReactiveMongoRepository.

This interface automatically provides reactive versions of common operations, returning Mono for single results and Flux for multiple results.

import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface ProductRepository extends ReactiveMongoRepository<Product, String> {
  // Custom reactive query methods can be added here
  Mono<Product> findByName(String name);
  Flux<Product> findByPriceGreaterThan(double price);
}

Simulating Reactive Save

When you save an entity using a reactive repository, it returns a Mono<Product>. This Mono represents the product once it's saved. You subscribe to it to trigger the operation and handle the result.

Try running this example to see how a reactive save operation might be handled:

import reactor.core.publisher.Mono;

class Item {
  String id;
  String name;
  public Item(String id, String name) {
    this.id = id;
    this.name = name;
  }
  @Override
  public String toString() { return "Item{name='" + name + "'} "; }
}

public class Main {
  public static void main(String[] args) {
    Item newItem = new Item("101", "Reactive Widget");

    // Simulate a reactive repository save method
    Mono<Item> savedItemMono = Mono.just(newItem)
                                   .doOnSuccess(item -> System.out.println("Simulating DB save for: " + item.name));

    System.out.println("Initiating save operation...");
    savedItemMono.subscribe(
      item -> System.out.println("Saved item received: " + item),
      error -> System.err.println("Error: " + error.getMessage()),
      () -> System.out.println("Save process completed.")
    );
  }
}

Simulating Reactive Retrieval

Retrieving data reactively works similarly. For a single item (e.g., by ID), you get a Mono. For multiple items, you get a Flux. You subscribe to these publishers to consume the data.

Run this code to see how Mono and Flux are used to handle retrieved data:

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;

class User {
  String id;
  String name;
  public User(String id, String name) {
    this.id = id;
    this.name = name;
  }
  @Override
  public String toString() { return "User{name='" + name + "'} "; }
}

public class Main {
  public static void main(String[] args) {
    List<User> users = Arrays.asList(
      new User("U1", "Alice"),
      new User("U2", "Bob"),
      new User("U3", "Charlie")
    );

    // Simulate finding a single user by ID
    Mono<User> userMono = Mono.just(users.get(0));
    System.out.println("\n--- Finding single user ---");
    userMono.subscribe(user -> System.out.println("Found: " + user));

    // Simulate finding all users
    Flux<User> userFlux = Flux.fromIterable(users);
    System.out.println("\n--- Finding all users ---");
    userFlux.subscribe(user -> System.out.println("Found: " + user));
  }
}

Integrating with Reactive Services

In a Spring WebFlux application, your service layer will inject the reactive repositories and use their Mono and Flux return types. This allows for seamless chaining of reactive operations.

For example, a service method might save a product and then return the saved product's ID, all within a reactive stream.

import reactor.core.publisher.Mono;
// Assume Product and ProductRepository are defined elsewhere
// import your.package.Product;
// import your.package.ProductRepository;

// This is a simplified example, not a full runnable app
// as it would require a full Spring Boot context.
class ProductService {
  private final ProductRepository productRepository;

  public ProductService(ProductRepository productRepository) {
    this.productRepository = productRepository;
  }

  public Mono<String> createProduct(Product product) {
    return productRepository.save(product)
                            .map(Product::getId);
  }

  public Mono<Product> getProductById(String id) {
    return productRepository.findById(id);
  }
}

Chaining Reactive Data Operations

The true power of reactive data access comes when you chain operations. You can transform, filter, and combine Mono and Flux streams from your database with other reactive sources (like external API calls or other service logic).

This allows you to build complex, non-blocking data flows efficiently.

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;

public class Main {
  public static void main(String[] args) {
    // Simulate fetching user IDs from a database (Flux)
    Flux<String> userIds = Flux.just("userA", "userB", "userC");

    // Simulate fetching user details for each ID (Mono)
    Flux<String> userNames = userIds.delayElements(Duration.ofMillis(50))
                                    .flatMap(id -> Mono.just("Name_" + id.toUpperCase()));

    System.out.println("Fetching and transforming user data...");
    userNames.subscribe(
      name -> System.out.println("Processed User: " + name),
      error -> System.err.println("Error: " + error.getMessage()),
      () -> System.out.println("All users processed.")
    );

    // Keep main thread alive for async operations
    try { Thread.sleep(500); } catch (InterruptedException e) {} 
  }
}

Quick Check: Reactive Repositories

You are building a Spring WebFlux application and need to connect to a MongoDB database in a non-blocking way. Which Spring Data interface should you extend for your repository to get reactive CRUD operations?

Recap: Reactive Data Access

Great job! In this lesson, you've learned about the importance of reactive data access in Spring WebFlux applications and how to achieve it.

  • Traditional blocking data access is replaced by non-blocking reactive drivers.
  • Spring Data provides interfaces like ReactiveMongoRepository for reactive CRUD.
  • These repositories return Mono (for single items) and Flux (for multiple items).
  • You can seamlessly chain reactive operations from data access with other reactive components.

This knowledge is key to building truly end-to-end reactive applications!

자주 묻는 질문

“리액티브 데이터 접근 및 통합” 강의는 무료인가요?

네 — “리액티브 데이터 접근 및 통합” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Spring Boot 4 Complete Guide 강의 전체를 잠금 해제할 수 있습니다. Spring Boot 4 Complete Guide 강의에는 총 4개의 강의가 포함되어 있습니다.

“리액티브 데이터 접근 및 통합”에서 뭘 배우나요?

WebFlux 애플리케이션을 리액티브 데이터 저장소에 연결하고 다른 리액티브 구성 요소와 통합합니다. 브라우저에서 직접 실행하는 실습 코드로 Spring Boot 4 Complete Guide을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Spring Boot 4 Complete Guide을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Spring Boot 4 Complete Guide은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“리액티브 데이터 접근 및 통합” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Spring Boot 4 Complete Guide 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Spring Boot 4 Complete Guide 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 리액티브 프로그래밍 입문
  2. Spring WebFlux 및 Reactor Core
  3. 리액티브 데이터 접근 및 통합
  4. 리액티브 스트림의 백프레셔와 오류 처리
← Spring Boot 4 Complete Guide(으)로 돌아가기