Saving Superheroes reactively: Reactive JDBC with Micronaut
Reactive JDBC with Micronaut
In the last lecture, we saw how to save the superheroes in the database. While it is fine to give a home (Database) to our superheroes, We don't want them to wait for any housekeeping work to get their work done or even while calling. Think of it as a limited number of people doing work for a lot of guys waiting in the queue. While the paperwork of the previous one has not been done, the one behind will have to wait. Similarly, JDBC operations limit our capabilities. We will wait for the thread to complete the current execution so that the connection is free and returned to the pool for the next one to be used.
If you like my articles you can support me by sharing the articles with your friends, Twitter, Facebook, or any other social media. You can also buy me a coffee
Let us see how reactive jdbc connections can reduce our work. You can find the source code of working application at GitHub https://github.com/CODINGSAINT/super-heroes/tree/03.ReactiveJDBC
In this section we will :
Add dependency for Reactive JDBC
Create a Reactive Repository
Create Reactive Controller and CRUD end points
Add dependency for Reactive JDBC
We require few dependencies which enable us to be reactive. Add the following dependency to the pom file
<!-- 03. Reactive Dependency -->
<dependency>
<groupId>io.micronaut.data</groupId>
<artifactId>micronaut-data-r2dbc</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.reactor</groupId>
<artifactId>micronaut-reactor</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 03. Reactive Dependecy ends-->
Here micronaut-data-r2dbc
is micronaut dependency for reactive jdbc, r2dbc-h2
is for H2 DB reactive client and micronaut-reactor
is for project reactor from Spring
. Do note you can use the reactive java rather than project reactor but as per micronaut
Most R2DBC drivers are implemented in Project Reactor which has the ability to propagate a context across reactive operators and Micronaut Data R2DBC will populate this context and ensure the transaction is re-used if it is found within it.
However, it is still pretty easy for the context to be lost since different libraries that implement Reactive Streams don’t propagate contexts between each other so if you include RxJava or any other reactive operator library it is likely the context will be lost.
Source : https://micronaut-projects.github.io/micronaut-r2dbc/1.0.x/guide/
Create a Reactive Repository
Now we will create the reactive repository to facilitate CRUD operations. In the below code, we extend to ReactiveStreamsCrudRepository
. We have overridden findBy
with Mono
and findAll
with Flux
.
@JdbcRepository(dialect = Dialect.H2)
public interface ReactiveSuperheroRepository extends ReactiveStreamsCrudRepository<Superhero, Long> {
@NonNull
@Override
Mono<Superhero> findById(@NonNull Long aLong);
@NonNull
@Override
Flux<Superhero> findAll();
}
Create Reactive Controller and CRUD endpoints
Let us create few endpoints. We will start with creating a new controller with the prefix "rx" . It will help us to know the difference between those who are using only JDBC template and the ones which have reactive
implemented.
Controller
We will create ReactiveSuperHeroController
with ReactiveSuperheroRepository
injected to it.
@Controller("rx/")
public class ReactiveSuperHeroController {
private ReactiveSuperheroRepository reactiveSuperheroRepository;
public ReactiveSuperHeroController(ReactiveSuperheroRepository reactiveSuperheroRepository) {
this.reactiveSuperheroRepository = reactiveSuperheroRepository;
}
}
Now we will add the endpoints
POST to create a superhero
@Post("/superhero")
Single<Superhero> create(@Valid Superhero superhero) {
return Single.fromPublisher(reactiveSuperheroRepository.save(superhero));
}
GET to retrieve a superhero by id
@Get("superhero/{id}")
public Mono<Superhero> superheroesById(Long id) {
return reactiveSuperheroRepository.findById(id);
}
GET to retrieve all superheroes
@Get("superheroes")
public Flux<Superhero> superheroes() {
return reactiveSuperheroRepository.findAll();
}
PUT to update superhero
@Put("superhero")
Single<Superhero> update( @Valid Superhero superhero) {
return Single.fromPublisher(reactiveSuperheroRepository.update(superhero));
}
DELETE to purge the superhero
@Delete("superhero/{id}")
Single<HttpResponse<?>> update(@NotNull Long id) {
return Single
.fromPublisher(reactiveSuperheroRepository.deleteById(id))
.map(deleted->deleted>0?HttpResponse.noContent():HttpResponse.notFound());
}
Now you can test all of these working endpoints in POSTMAN or any other client of your choice.