Use Spring Data R2DBC + Postgres to realize the function of adding deleting modifying and checking

  • 2021-09-05 00:08:00
  • OfStack

In this tutorial, I want to show you how to perform various Postgres CRUD operations with Spring WebFlux Spring Data R2DBC.

R2DBC stands for a reactive relational database connection.

Like JPA (Java persistent API) 1, R2DBC is a specification for reactive drivers for relational databases. Since it is a separate specification, do not compare it with JPA/Hibernate features such as @ OneToMany, @ ManyToMany, and so on.

We will develop an Spring Boot application called product-service, which is responsible for creating new products/retrieving all products/deleting or updating existing products to perform various Postgres CRUD operations of R2DBC.

Entity class


@Data
@ToString
<b>public</b> <b>class</b> Product {

 @Id
 <b>private</b> Integer id;
 <b>private</b> String description;
 <b>private</b> Double price;
 
}

We can't add @ Entity here because this is not JPA.

Spring Data Reactivity Repository

Spring Data does all the heavy work as usual. We need to create a repository for our entity classes by extending ReactiveCrudRepository.


<b>import</b> org.springframework.data.repository.reactive.ReactiveCrudRepository;
<b>import</b> org.springframework.stereotype.Repository;

@Repository
<b>public</b> <b>interface</b> ProductRepository <b>extends</b> ReactiveCrudRepository<Product, Integer> {
}

CRUD operation

Let's create a service class to perform the Postgres CRUD operation via Spring Data Reactive Repository.


@Service
<b>public</b> <b>class</b> ProductService {

 @Autowired
 <b>private</b> ProductRepository repository;

 <b>public</b> Flux<Product> getAllProducts(){
 <b>return</b> <b>this</b>.repository.findAll();
 }

 <b>public</b> Mono<Product> getProductById(<b>int</b> productId){
 <b>return</b> <b>this</b>.repository.findById(productId);
 }

 <b>public</b> Mono<Product> createProduct(<b>final</b> Product product){
 <b>return</b> <b>this</b>.repository.save(product);
 }

 <b>public</b> Mono<Product> updateProduct(<b>int</b> productId, <b>final</b> Mono<Product> productMono){
 <b>return</b> <b>this</b>.repository.findById(productId)
  .flatMap(p -> productMono.map(u -> {
   p.setDescription(u.getDescription());
   p.setPrice(u.getPrice());
   <b>return</b> p;
  }))
  .flatMap(p -> <b>this</b>.repository.save(p));
 }

 <b>public</b> Mono<Void> deleteProduct(<b>final</b> <b>int</b> id){
 <b>return</b> <b>this</b>.repository.deleteById(id);
 }

}

REST API

It's time to expose the service through REST API:


@RestController
@RequestMapping(<font>"product"</font><font>)
<b>public</b> <b>class</b> ProductController {

 @Autowired
 <b>private</b> ProductService productService;

 @GetMapping(</font><font>"all"</font><font>)
 <b>public</b> Flux<Product> getAll(){
 <b>return</b> <b>this</b>.productService.getAllProducts();
 }

 @GetMapping(</font><font>"{productId}"</font><font>)
 <b>public</b> Mono<ResponseEntity<Product>> getProductById(@PathVariable <b>int</b> productId){
 <b>return</b> <b>this</b>.productService.getProductById(productId)
    .map(ResponseEntity::ok)
    .defaultIfEmpty(ResponseEntity.notFound().build());
 }

 @PostMapping
 <b>public</b> Mono<Product> createProduct(@RequestBody Mono<Product> productMono){
 <b>return</b> productMono.flatMap(<b>this</b>.productService::createProduct);
 }

 @PutMapping(</font><font>"{productId}"</font><font>)
 <b>public</b> Mono<Product> updateProduct(@PathVariable <b>int</b> productId,
     @RequestBody Mono<Product> productMono){
 <b>return</b> <b>this</b>.productService.updateProduct(productId, productMono);
 }

 @DeleteMapping(</font><font>"/{id}"</font><font>)
 <b>public</b> Mono<Void> deleteProduct(@PathVariable <b>int</b> id){
 <b>return</b> <b>this</b>.productService.deleteProduct(id);
 }

}
</font>

Configure

This configuration is required for the Spring Data reaction driver to connect to Postgres DB.

Method 1: Use application. properties


spring.r2dbc.url=r2dbc:postgresql:<font><i>//localhost:5432/productdb</i></font><font>
spring.r2dbc.username=vinsguru
spring.r2dbc.password=admin
</font>

Method 2: Expose the connection factory bean


@Configuration
<b>public</b> <b>class</b> R2DBCConfig {

 @Bean
 <b>public</b> ConnectionFactory connectionFactory() {
 <b>return</b> ConnectionFactories.get(
  ConnectionFactoryOptions.builder()
   .option(DRIVER, <font>"postgresql"</font><font>)
   .option(HOST, </font><font>"localhost"</font><font>)
   .option(PORT, 5432)
   .option(USER, </font><font>"vinsguru"</font><font>)
   .option(PASSWORD, </font><font>"admin"</font><font>)
   .option(DATABASE, </font><font>"productdb"</font><font>)
   .option(MAX_SIZE, 40)
   .build());
 }

}
</font>

The complete source code is here.


Related articles: