Spring Boot with R2DBC — CRUD Operations
By: Rishi Sharma
Tags: Postgres, Spring Boot, Webflux, Spring Framework, R2dbc

Today we’ll learn about connecting to SQL (Relational) databases with reactive repositories with spring boot. In this project i’ll be using

Spring boot 2.3.0.RELEASE

PostgreSQL for database

Project Setup

application.properties

spring.r2dbc.url=r2dbc:pool:postgresql://localhost:6432/r2dbc

spring.r2dbc.username=username

spring.r2dbc.password=password

Creating Entity

import org.springframework.data.annotation.Id;

import org.springframework.data.relational.core.mapping.Table; @Table

public class Employee {



@Id

private Long id;



private String name;



private String department;



}

SQL Code for creating employee table

CREATE TABLE employee(

id bigserial NOT NULL,

name character varying(255) ,

department character varying(255) ,

CONSTRAINT pk_emp_id PRIMARY KEY (id)

);

Notice that, annotation @Id comes from spring data and not from java persistence when we use spring data jpa. Also, we have used bigserial as the data type for id to make auto-increment. By default behaviour when we use spring r2dbc will be, if field which contains @Id annotation is considered as identifier for entity and if that field is empty then it is considered as new entity and triggers insert operation when we call save() function of repository. But if the identifier field is non empty then it’s considered as not a new entity and will trigger update. So, if we don’t use bigserial and try to save the entity with id field not null, then it’ll trigger update and will throw that unable to update row with identifier. That’s why we used bigserial .

Repository

import org.springframework.data.repository.reactive.ReactiveCrudRepository;



public interface EmployeeRepository extends ReactiveCrudRepository<Employee, Long> {

}

Here, we have used ReactiveCrudRepository to extend our EmployeeRepository. It gives reactive implementation of accessing relational databases.

Controller

@RestController

@RequestMapping("/employees")

public class EmployeeController {



@Autowired

private EmployeeRepository employeeRepository; }

Now we’ll add endpoints for CRUD operations.

Add Employee

Adding an employee

@PostMapping

public Mono<Employee> saveEmployee(@RequestBody Employee employee){

return employeeRepository.save(employee);

}

As discussed previously, when we want to create new entity then we will not supply any data in id field and it’ll be auto-generated by database.

Read Employee

//fetch employee by id

@GetMapping("/{id}")

public Mono<Employee> findOne(@PathVariable("id") Long id){

return employeeRepository.findById(id);

} //fetch all employee

@GetMapping

public Flux<Employee> findAll(){

return employeeRepository.findAll();

}

Get employee by id

When we want to find single entity, then we can use findById() which will return Mono (when we want to emit 0 or 1 element). Alternatively, if we want to emit more than 1 element then we can use Flux, as showed in above example with findAll() .

Update Employee

@PutMapping

public Mono<Employee> updateEmployee(@RequestBody Employee employee){

return employeeRepository.save(employee);

}

Update employee

Now, here we want to update then entity so we’ll supply id which will help identify which row we want to update in database.

Delete Employee

@DeleteMapping("/{id}")

public Mono<Employee> deleteEmployee(@PathVariable("id") Long id){

return employeeRepository.findById(id)

.doOnSuccess(employee -> employeeRepository.delete(employee).subscribe());

}

Delete employee by id

Here, we call subscribe() on delete() function of repository, because if don’t use subscribe then it’ll not call execute this function. delete() returns Mono<Void> , mono/flux will only executed when there is someone to consume it, else they will not be executed. So when we call subscribe() over mono then only it executes. In other cases we didn’t call subscribe() because we directly returned mono, here we don’t return the mono which is returned by delete() , instead we return the mono from findById() that’s why we didn’t call subscribe() over this mono.

That’s it !

Your reactive relational database repositories are working.

Code is available on github : https://github.com/rsbeoriginal/r2dbc