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) FluxfindByFirstName(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 .