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

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

1. Вступление

В этом руководстве мы увидим, как настроить и реализовать операции с базой данных с помощью реактивного программирования через Spring Data Reactive Repositories с MongoDB.

Мы рассмотрим основные способы использованияReactiveCrudRepository,ReactiveMongoRepository,, а такжеReactiveMongoTemplate.

Несмотря на то, что в этих реализациях используетсяreactive programming, это не является основной темой данного руководства.

2. Среда

Чтобы использовать Reactive MongoDB, нам нужно добавить зависимость к нашемуpom.xml.

Мы также добавим встроенный MongoDB для тестирования:


    // ...
    
        org.springframework.boot
        spring-boot-starter-data-mongodb-reactive
    
    
        de.flapdoodle.embed
        de.flapdoodle.embed.mongo
        test
    

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

Чтобы активировать реактивную поддержку, нам нужно использовать@EnableReactiveMongoRepositories вместе с некоторой настройкой инфраструктуры:

@EnableReactiveMongoRepositories
public class MongoReactiveApplication
  extends AbstractReactiveMongoConfiguration {

    @Bean
    public MongoClient mongoClient() {
        return MongoClients.create();
    }

    @Override
    protected String getDatabaseName() {
        return "reactive";
    }
}

Обратите внимание, что вышеперечисленное было бы необходимо, если бы мы использовали автономную установку MongoDB. Но поскольку в нашем примере мы используем Spring Boot со встроенным MongoDB, указанная выше конфигурация не требуется.

4. СозданиеDocument

Для примеров ниже давайте создадим классAccount и аннотируем его@Document, чтобы использовать его в операциях с базой данных:

@Document
public class Account {

    @Id
    private String id;
    private String owner;
    private Double value;

    // getters and setters
}

5. Использование реактивных репозиториев

Мы уже знакомы сrepositories programming model, с уже определенными методами CRUD, а также с поддержкой некоторых других общих вещей.

Теперь с реактивной моделью мы получаем тот же набор методов и спецификаций, за исключением того, что мы будем реагировать на результаты и параметры.

5.1. ReactiveCrudRepositoryс

Мы можем использовать этот репозиторий так же, как блокирующийCrudRepository:

@Repository
public interface AccountCrudRepository
  extends ReactiveCrudRepository {

    Flux findAllByValue(String value);
    Mono findFirstByOwner(Mono owner);
}

Мы можем передавать различные типы аргументов, такие как простой (String), завернутый (Optional,Stream) или реактивный (Mono,Flux), как мы можем см. в методеfindFirstByOwner().

5.2. ReactiveMongoRepositoryс

Также есть интерфейсReactiveMongoRepository, который наследуется отReactiveCrudRepository и добавляет несколько новых методов запроса:

@Repository
public interface AccountReactiveRepository
  extends ReactiveMongoRepository { }

ИспользуяReactiveMongoRepository, мы можем запросить на примере:

Flux accountFlux = repository
  .findAll(Example.of(new Account(null, "owner", null)));

В результате мы получим каждыеAccount, которые совпадают с прошедшим примером.

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

Mono accountMono
  = repository.save(new Account(null, "owner", 12.3));
Mono accountMono2 = repository
  .findById("123456");

5.3. RxJava2CrudRepositoryс

СRxJava2CrudRepository, мы имеем то же поведение, что иReactiveCrudRepository,, но с результатами и типами параметров изRxJava:

@Repository
public interface AccountRxJavaRepository
  extends RxJava2CrudRepository {

    Observable findAllByValue(Double value);
    Single findFirstByOwner(Single owner);
}

5.4. Тестирование наших основных операций

Чтобы протестировать наши методы репозитория, мы будем использовать тестового подписчика:

@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
    repository.save(new Account(null, "Bill", 12.3)).block();
    Flux accountFlux = repository.findAllByValue(12.3);

    StepVerifier
      .create(accountFlux)
      .assertNext(account -> {
          assertEquals("Bill", account.getOwner());
          assertEquals(Double.valueOf(12.3) , account.getValue());
          assertNotNull(account.getId());
      })
      .expectComplete()
      .verify();
}

@Test
public void givenOwner_whenFindFirstByOwner_thenFindAccount() {
    repository.save(new Account(null, "Bill", 12.3)).block();
    Mono accountMono = repository
      .findFirstByOwner(Mono.just("Bill"));

    StepVerifier
      .create(accountMono)
      .assertNext(account -> {
          assertEquals("Bill", account.getOwner());
          assertEquals(Double.valueOf(12.3) , account.getValue());
          assertNotNull(account.getId());
      })
      .expectComplete()
      .verify();
}

@Test
public void givenAccount_whenSave_thenSaveAccount() {
    Mono accountMono = repository.save(new Account(null, "Bill", 12.3));

    StepVerifier
      .create(accountMono)
      .assertNext(account -> assertNotNull(account.getId()))
      .expectComplete()
      .verify();
}

6. ReactiveMongoTemplateс

Помимо подхода к репозиториям, у нас естьReactiveMongoTemplate.

Прежде всего, нам нужно зарегистрироватьReactiveMongoTemplate как bean-компонент:

@Configuration
public class ReactiveMongoConfig {

    @Autowired
    MongoClient mongoClient;

    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate() {
        return new ReactiveMongoTemplate(mongoClient, "test");
    }
}

И затем мы можем внедрить этот bean-компонент в наш сервис для выполнения операций с базой данных:

@Service
public class AccountTemplateOperations {

    @Autowired
    ReactiveMongoTemplate template;

    public Mono findById(String id) {
        return template.findById(id, Account.class);
    }

    public Flux findAll() {
        return template.findAll(Account.class);
    }
    public Mono save(Mono account) {
        return template.save(account);
    }
}

ReactiveMongoTemplate также имеет ряд методов, которые не относятся к нашему домену, вы можете проверить их вdocumentation.

7. Заключение

В этом кратком руководстве мы рассмотрели использование репозиториев и шаблонов с использованием реактивного программирования с использованием MongoDB и среды Spring Data Reactive Repositories.

Полный исходный код примеров доступенover on GitHub.