1. 개요

이 예제에서는 Spring Data Repositories를 사용하여 Couchbase에서 반응형 방식으로 데이터베이스 작업을 구성하고 구현하는 방법을 배웁니다.

ReactiveCrudRepository  및  ReactiveSortingRepository 의 기본 사용법을 다룰 것  입니다. 또한 AbstractReactiveCouchbaseConfiguration 으로 테스트 애플리케이션을 구성합니다 .

2. 메이븐 의존성

먼저 필요한 의존성을 추가해 보겠습니다.

<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-couchbase-reactive</artifactId>
</dependency>

spring-boot-starter-data-couchbase-reactive 의존성에는 반응형 API를 사용하여 Couchbase에서 작동하는 데 필요한 모든 것이 포함되어 있습니다 .

Project Reactor API를 사용하기 위해 reactor-core 의존성 도 포함합니다 .

3. 구성

다음으로 Couchbase와 애플리케이션 간의 연결 설정을 정의하겠습니다.

속성을 보유할 클래스를 생성하여 시작하겠습니다.

@Configuration
public class CouchbaseProperties {

    private List<String> bootstrapHosts;
    private String bucketName;
    private String bucketPassword;
    private int port;

    public CouchbaseProperties(
      @Value("${spring.couchbase.bootstrap-hosts}") List<String> bootstrapHosts, 
      @Value("${spring.couchbase.bucket.name}") String bucketName, 
      @Value("${spring.couchbase.bucket.password}") String bucketPassword, 
      @Value("${spring.couchbase.port}") int port) {
        this.bootstrapHosts = Collections.unmodifiableList(bootstrapHosts);
        this.bucketName = bucketName;
        this.bucketPassword = bucketPassword;
        this.port = port;
    }

    // getters
}

반응적 지원을 사용하려면 AbstractReactiveCouchbaseConfiguration 을 확장할 구성 클래스를 만들어야 합니다 .

@Configuration
@EnableReactiveCouchbaseRepositories("com.baeldung.couchbase.domain.repository")
public class ReactiveCouchbaseConfiguration extends AbstractReactiveCouchbaseConfiguration {

    private CouchbaseProperties couchbaseProperties;

    public ReactiveCouchbaseConfiguration(CouchbaseProperties couchbaseProperties) {
        this.couchbaseProperties = couchbaseProperties;
    }

    @Override
    protected List<String> getBootstrapHosts() {
        return couchbaseProperties.getBootstrapHosts();
    }

    @Override
    protected String getBucketName() {
        return couchbaseProperties.getBucketName();
    }

    @Override
    protected String getBucketPassword() {
        return couchbaseProperties.getBucketPassword();
    }

    @Override
    public CouchbaseEnvironment couchbaseEnvironment() {
        return DefaultCouchbaseEnvironment
          .builder()
          .bootstrapHttpDirectPort(couchbaseProperties.getPort())
          .build();
    }
}

또한 @EnableReactiveCouchbaseRepositories 를 사용하여 지정된 패키지 아래에 있을 반응형 저장소를 활성화했습니다.

또한 Couchbase 연결 포트를 전달하기 위해 couchbaseEnvironment() 를 재정의했습니다.

4. 저장소

이 섹션에서는 반응형 저장소를 만들고 사용하는 방법을 배웁니다. 기본적으로 "all" 보기 는 대부분의 CRUD 작업을 지원합니다. 사용자 정의 리포지토리 방법은 N1QL 에서 지원합니다 . 클러스터가 N1QL을 지원하지 않는 경우 초기화 중에 UnsupportedCouchbaseFeatureException 이 발생합니다.

먼저 리포지토리가 작동할 POJO 클래스를 생성해 보겠습니다.

@Document
public class Person {
    @Id private UUID id;
    private String firstName;

   //getters and setters
}

4.1. 보기 기반 저장소

이제 Person 에 대한 저장소를 생성합니다 .

@Repository
@ViewIndexed(designDoc = ViewPersonRepository.DESIGN_DOCUMENT)
public interface ViewPersonRepository extends ReactiveCrudRepository<Person, UUID> {

    String DESIGN_DOCUMENT = "person";
}

리포지토리는   Reactor API를 사용하여 Couchbase와 상호 작용하기 위해 ReactiveCrudRepository 인터페이스를 확장합니다.

또한 사용자 지정 메서드를 추가하고 @View 어노테이션을 사용하여 보기 기반으로 만들 수 있습니다.

@View(designDocument = ViewPersonRepository.DESIGN_DOCUMENT)
Flux<Person> findByFirstName(String firstName);

기본적으로 쿼리는 byFirstName 이라는 보기를 찾습니다 . 사용자 지정 보기 이름을 제공하려면 viewName 인수 를 사용해야 합니다 .

마지막으로 테스트 구독자의 도움을 받아 간단한 CRUD 테스트를 만들어 보겠습니다.

@Test
public void shouldSavePerson_findById_thenDeleteIt() {
    final UUID id = UUID.randomUUID();
    final Person person = new Person(id, "John");
    personRepository
      .save(person)
      .subscribe();
 
    final Mono<Person> byId = personRepository.findById(id);
 
    StepVerifier
      .create(byId)
      .expectNextMatches(result -> result
        .getId()
        .equals(id))
      .expectComplete()
      .verify();
 
    personRepository
      .delete(person)
      .subscribe();
}

4.2. N1QL/보기 기반 리포지토리

이제 N1QL 쿼리를 사용할 Person 용 반응 저장소를 생성 합니다.

@Repository
@N1qlPrimaryIndexed
public interface N1QLPersonRepository extends ReactiveCrudRepository<Person, UUID> {
    Flux<Person> findAllByFirstName(String firstName);
}

리포지토리 는 Reactor API도 사용하기 위해 ReactiveCrudRepository 를 확장합니다. 또한 N1QL 지원 쿼리를 생성하는 사용자 지정 findAllByFirstName 메서드를 추가 했습니다.

그런 다음 findAllByFirstName 메서드 에 대한 테스트를 추가해 보겠습니다  .

@Test
public void shouldFindAll_byLastName() {
    final String firstName = "John";
    final Person matchingPerson = new Person(UUID.randomUUID(), firstName);
    final Person nonMatchingPerson = new Person(UUID.randomUUID(), "NotJohn");
    personRepository
      .save(matchingPerson)
      .subscribe();
    personRepository
      .save(nonMatchingPerson)
      .subscribe();
 
    final Flux<Person> allByFirstName = personRepository.findAllByFirstName(firstName);
 
    StepVerifier
      .create(allByFirstName)
      .expectNext(matchingPerson)
      .verifyComplete();
}

또한 정렬 추상화를 사용하여 사람을 검색할 수 있는 저장소를 만들 것입니다.

@Repository
public interface N1QLSortingPersonRepository extends ReactiveSortingRepository<Person, UUID> {
    Flux<Person> findAllByFirstName(String firstName, Sort sort);
}

마지막으로 데이터가 실제로 정렬되었는지 확인하는 테스트를 작성해 보겠습니다.

@Test
public void shouldFindAll_sortedByFirstName() {
    final Person firstPerson = new Person(UUID.randomUUID(), "John");
    final Person secondPerson = new Person(UUID.randomUUID(), "Mikki");
    personRepository
      .save(firstPerson)
      .subscribe();
    personRepository
      .save(secondPerson)
      .subscribe();
 
    final Flux<Person> allByFirstName = personRepository
      .findAll(Sort.by(Sort.Direction.DESC, "firstName"));
 
    StepVerifier
      .create(allByFirstName)
      .expectNextMatches(person -> person
        .getFirstName()
        .equals(secondPerson.getFirstName()))
      .expectNextMatches(person -> person
        .getFirstName()
        .equals(firstPerson.getFirstName()))
      .verifyComplete();
}

5. 결론

이 기사에서는 Couchbase 및 Spring Data Reactive 프레임워크를 사용한 반응형 프로그래밍을 사용하여 리포지토리를 사용하는 방법을 배웠습니다.

항상 그렇듯이 이러한 예제의 코드는 Github에서 사용할 수 있습니다 .

Persistence footer banner