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 ListbootstrapHosts; 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 ListgetBootstrapHosts() { 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 MonobyId = 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 FluxallByFirstName = 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 FluxallByFirstName = 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 .