1. Въведение
В този урок ще видим как да конфигурираме и прилагаме операции с база данни, използвайки реактивно програмиране чрез Spring Data Reactive Repositories с MongoDB.
Ще разгледаме основните употреби на ReactiveCrud Хранилище, ReactiveMongoRepository , както и ReactiveMongoTemplate.
Въпреки че тези реализации използват реактивно програмиране, това не е основният фокус на този урок.
2. Околна средата
За да използваме Reactive MongoDB, трябва да добавим зависимостта към нашия pom.xml.
Ще добавим и вграден MongoDB за тестване:
<dependencies>
// ...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
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 за да го използвате в операциите с базата данни:
@Document
public class Account {
@Id
private String id;
private String owner;
private Double value;
// getters and setters
}
5. Използване на реактивни хранилища
Вече сме запознати с модела за програмиране на хранилища, с вече дефинираните CRUD методи плюс поддръжка за някои други често срещани неща.
Сега с реактивния модел получаваме същия набор от методи и спецификации, с изключение на това, че ще се справим с резултатите и параметрите по реактивен начин.
5.1. ReactiveCrudRepository
Можем да използваме това хранилище по същия начин като блокиращото CrudRepository :
@Repository
public interface AccountCrudRepository
extends ReactiveCrudRepository<Account, String> {
Flux<Account> findAllByValue(String value);
Mono<Account> findFirstByOwner(Mono<String> owner);
}
Можем да предаваме различни типове аргументи като обикновен (String ), опакован (По избор , Поток ) или реактивен (Моно , Поток ), както можем да видим в findFirstByOwner() метод.
5.2. ReactiveMongoRepository
Има и ReactiveMongoRepository интерфейс, който наследява от ReactiveCrudRepository и добавя някои нови методи на заявка:
@Repository
public interface AccountReactiveRepository
extends ReactiveMongoRepository<Account, String> { }
Използване на ReactiveMongoRepository , можем да правим заявка чрез пример:
Flux<Account> accountFlux = repository
.findAll(Example.of(new Account(null, "owner", null)));
В резултат на това ще получим всеки Профил това е същото като предания пример.
Със създадените ни хранилища те вече имат дефинирани методи за извършване на някои операции с база данни, които не е необходимо да прилагаме:
Mono<Account> accountMono
= repository.save(new Account(null, "owner", 12.3));
Mono<Account> accountMono2 = repository
.findById("123456");
5.3. RxJava2CrudRepository
С RxJava2CrudRepository, имаме същото поведение като ReactiveCrudRepository, но с резултатите и типове параметри от RxJava :
@Repository
public interface AccountRxJavaRepository
extends RxJava2CrudRepository<Account, String> {
Observable<Account> findAllByValue(Double value);
Single<Account> findFirstByOwner(Single<String> owner);
}
5.4. Тестване на нашите основни операции
За да тестваме нашите методи за хранилище, ще използваме тестовия абонат:
@Test
public void givenValue_whenFindAllByValue_thenFindAccount() {
repository.save(new Account(null, "Bill", 12.3)).block();
Flux<Account> 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<Account> 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<Account> accountMono = repository.save(new Account(null, "Bill", 12.3));
StepVerifier
.create(accountMono)
.assertNext(account -> assertNotNull(account.getId()))
.expectComplete()
.verify();
}
6. ReactiveMongoTemplate
Освен подхода към хранилищата, имаме ReactiveMongoTemplate .
На първо място, трябва да регистрираме ReactiveMongoTemplate като боб:
@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<Account> findById(String id) {
return template.findById(id, Account.class);
}
public Flux<Account> findAll() {
return template.findAll(Account.class);
}
public Mono<Account> save(Mono<Account> account) {
return template.save(account);
}
}
ReactiveMongoTemplate също има редица методи, които не са свързани с домейна, който имаме, можете да ги проверите в документацията.