Рубрики
Без рубрики

Реактивные хранилища данных Spring с Couchbase

Узнайте, как настроить и реализовать операции с базами данных реактивным способом на Couchbase с помощью хранилищ данных Spring

Автор оригинала: Łukasz Ryś.

1. Обзор

В этом уроке мы узнаем, как настроить и реализовать операции с базами данных реактивным способом на Couchbase с использованием хранилищ данных Spring.

Мы рассмотрим основные способы использования Reactive CrudRepository и Репозитория реактивной сортировки . Кроме того, мы настроим наше тестовое приложение с помощью Абстрактной реактивной конфигурации Couchbase .

2. Зависимости Maven

Во-первых, давайте добавим необходимые зависимости:


    io.projectreactor
    reactor-core


    org.springframework.boot
    spring-boot-starter-data-couchbase-reactive

Зависимость spring-boot-starter-data-couchbase-reactive содержит все, что нам нужно для работы с Couchbase с помощью реактивного API.

Мы также включим зависимость reactor-core для использования API Project Reactor.

3. Конфигурация

Далее давайте определим параметры подключения между Couchbase и нашим приложением.

Давайте начнем с создания класса, который будет содержать наши свойства:

@Configuration
public class CouchbaseProperties {

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

    public CouchbaseProperties(
      @Value("${spring.couchbase.bootstrap-hosts}") List 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 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 для включения наших реактивных репозиториев, которые будут находиться в указанном пакете.

Кроме того, мы переопределили couchbaseEnvironment () , чтобы передать порт подключения Couchbase.

4. Хранилища

В этом разделе мы узнаем, как создавать и использовать реактивный репозиторий. По умолчанию “все” представление поддерживает большинство операций CRUD. Пользовательские методы репозитория поддерживаются N1QL . Если кластер не поддерживает N1QL, во время инициализации будет выдано исключение Неподдерживаемой функции Couchbase .

Во-первых, давайте создадим класс 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 {

    String DESIGN_DOCUMENT = "person";
}

Репозиторий расширяет интерфейс Reactive CrudRepository , чтобы использовать Reactor API для взаимодействия с Couchbase.

Кроме того, мы можем добавить пользовательский метод и использовать аннотацию @View , чтобы сделать его основанным на представлении:

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

По умолчанию запрос будет искать представление с именем по имени . Если мы хотим предоставить пользовательское имя представления, нам придется использовать аргумент имя представления .

Наконец, давайте создадим простой 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 byId = personRepository.findById(id);
 
    StepVerifier
      .create(byId)
      .expectNextMatches(result -> result
        .getId()
        .equals(id))
      .expectComplete()
      .verify();
 
    personRepository
      .delete(person)
      .subscribe();
}

4.2. Репозиторий на основе N1QL/Представлений

Теперь мы создадим реактивный репозиторий для Person , который будет использовать запросы N1QL:

@Repository
@N1qlPrimaryIndexed
public interface N1QLPersonRepository extends ReactiveCrudRepository {
    Flux findAllByFirstName(String firstName);
}

Репозиторий расширяет Reactive CrudRepository , чтобы также использовать API реактора. Кроме того, мы добавили пользовательский метод find All By First Name , который создает запрос с поддержкой N1QL.

После этого давайте добавим тест для метода find All By First Name :

@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 allByFirstName = personRepository.findAllByFirstName(firstName);
 
    StepVerifier
      .create(allByFirstName)
      .expectNext(matchingPerson)
      .verifyComplete();
}

Кроме того, мы создадим репозиторий, который позволит нам извлекать людей с помощью абстракции сортировки:

@Repository
public interface N1QLSortingPersonRepository extends ReactiveSortingRepository {
    Flux 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 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 framework.

Как всегда, код для этих примеров доступен на Github .