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에서 사용할 수 있습니다 .