Saving Superheroes reactively: Reactive JDBC with Micronaut

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 output-onlinepngtools.png


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.

Did you find this article valuable?

Support Kumar Pallav by becoming a sponsor. Any amount is appreciated!