Whether or not you've been actively developing within one of the or not, you've likely at least heard of the concept of by now. If not, I certainly encourage you to do a little research into the whole idea of using . JVM languages reactive programming declarative programming data streams In this article we'll take a look at the (very) brief background of not only what Reactive Relational Database Connectivity (R2DBC) is but it exists, and then dive into the code to see how the new can be used to create fully reactive, applications! why MariaDB R2DBC connector Java Spring We're going to walking through the process of creating a simple todo application, but if you'd prefer to jump directly into the code you can find it . here It all starts with Reactive Streams While I'm not going to give you the backstory and technical details behind reactive programming, it's important that we go over a few of the high level points before diving to all the hoopla. entire R2DBC For starters, it's important to know (or recall, depending on your current circumstance) that reactive programming boils down to the idea of using asynchronous data streams. A data stream is basically what it sounds like, a stream of data. But what does that really mean exactly? A stream is a sequence of ongoing events ordered in time. There are three types of events; value, error, completed signal. While we could certainly dive even deeper into the plethora of use cases for data streams, that's a little out of scope for this walk-through (I promise all of this is culminating to a walk-through). Instead we're going to focus on that the structure of a data stream is what brings the concept of to life. reactive streams Ok, ok, I know what you're thinking; "Damn, this dude is throwing around the word reactive more than a Midwesterner roaming through a crowd using the word ' '". Bear with me, there's a point to all this madness. I promise! ope Reactive Streams is simply a standard for asynchronous stream processing using the idea of non-blocking back pressure. "Seriously, Rob! Back pressure?! Are you just making things up now? I think I'm getting back pressure just reading this nonsense." No, I'm not just messing with you. You can think of back pressure as a way of the receiving side (of a data stream) telling the sending side when they are ready for more information and how much to send. Back pressure is an important concept because it's the foundation of which the reactive streams initiative is built on. Keeping out of the gritty details, the key takeaway here is that Reactive Streams is a set of specifications, or rules, used to define the way asynchronous streams are managed. - reactive streams creates a standard approach. TL;DR The following (very high level) diagram shows the interactions (to manage, yep, you guessed it, data streams!) between publishers and subscribers. For more information on reactive streams, specification came about, the interfaces involved and analysis on use cases, I encourage you to take a look at the . why this write-up by John Thompson For our purposes, we're interested in the specification itself, specifically how it's utilized with Reactive Relational Database Connectivity (R2DBC). R2DBC to the rescue R2DBC started as an experiment and proof of concept to enable integration of SQL databases into systems that use reactive programming models. It's necessary because of limitations of the API. Java Database Connectivity (JDBC) According to the : http://r2dbc.io "R2DBC specifies a that is intended to be implemented by driver vendors and used by client libraries. By using the R2DBC SPI, applications written in a JVM programming language can run SQL statements and retrieve results by using an underlying data source." service-provider interface (SPI) And if you haven't guess by now, the R2DBC SPI is based on and uses the concepts of publishers and subscribers to allow non-blocking back-pressure-aware data access. Ah, yes, we've come full circle! Reactive Streams - R2DBC is a new connectivity specification that supports reactive interactions all the way to the database level. TL;DR recently released their R2DBC connector implementation. It's completely and follows the MariaDB Corporation open-source R2DBC 0.8.1 specifications. This is where you ceremoniously crack your knuckles. It's time to code! Requirements Before jumping into code, you're going to need to make sure you have a few things on your machine: MariaDB Client Docker Java (v. 8+) (for testing the API endpoints) Curl Getting Started with MariaDB Let's assume you've either never used MariaDB or don't currently have an instance running on your machine. No problem! It only takes a couple of minutes, using a Docker container, to get MariaDB up and running. If you've already got an instance running feel free to skip down to the part where we create a new schema. To pull the and spin up a container simply open a terminal window and run the following: MariaDB Server image $ docker run -p 3306:3306 -d --name mariadb -eMARIADB_ROOT_PASSWORD=Password123! mariadb/server:10.4 The previous command will spin up a MariaDB Server container that you can connect to and communicate with using the . MariaDB client There are many SQL clients available out in the wild. For simplicity's sake, I've chosen to demonstrate how to use the official MariaDB Client, but certainly feel free to use whatever client you prefer. Connect to your MariaDB instance by executing the following command in a terminal window. You should see something like the following, which means you've successfully connected to the MariaDB instance! Next, create a new database for our TODO application. todo; CREATE DATABASE Then create a new table to store our tasks. todo.tasks ( , description ( ), completed ); CREATE TABLE id int varchar 200 boolean Getting reactive with R2DBC With a database instance spun up and schema created you're ready to create a fully-reactive application. Java Create a Maven project Start by navigating to , which will enable you to create a new -based project. https://start.spring.io Spring Maven For this project you can enter the following criteria. Next, add the following dependencies: Finally, click the "GENERATE" button to create and download the project (contained within a .zip file) to a desired location on your machine. Add the MariaDB R2DBC connector Navigate to the location where you downloaded the new Maven project (.zip file) to, and unzip. Then use a code editor to open the project, and open pom.xml. Add a new dependency for MariaDB's R2DBC connector to the collection of dependencies. org.mariadb r2dbc-mariadb 0.8.2-alpha2 < > dependency < > groupId </ > groupId < > artifactId </ > artifactId < > version </ > version </ > dependency The MariaDB R2DBC connector is not available in the Spring dependencies listing because it's currently still in the alpha phase of development. Preparing the data integration Now that you've created a project that contains all of the dependencies you'll need, it's time to start really coding. Typically, I like to start by creating the entity (or model) classes. Navigate to /src/main/java/com/example/todo , create a new folder called "models", and create a new file within it named "Task.java". Open "Task.java" and add the following code. com.mariadb.todo.models; org.springframework.data.relational.core.mapping.Table; lombok.Data; ( ) { Integer id; String description; Boolean completed; } package import import // Lombok annotation that eliminates getter/setter boilerplate code @Data // Annotation that will point to table "tasks" (pluralized in the database) @Table "tasks" public class Task @Id private private private Next, create a new folder called "repositories" in , and create a new filed within it named "TasksRepository.java" /src/main/java/com/mariadb/todo Open "TasksRepository.java" and add the following code. com.mariadb.todo.repositories; com.mariadb.todo.models.Task; org.springframework.data.repository.reactive.ReactiveCrudRepository; { } package import import // Registered as a Spring Repository (Component) // Repository = a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects public < , > interface TasksRepository extends ReactiveCrudRepository Task Integer The interface provides CRUD operations on a repository for a specific type, and follows reactive paradigms and uses types which are built on top of Reactive Streams. ReactiveCrudRepository Project Reactor Setting up the connection configuration As previously mentioned, in order to create a connection to a database using R2DBC you must first create a . The MariaDB implementation of the ConnectionFactory interface is called and it requires a instance, which contains a variety of configuration details used to connect to a MariaDB database instance. ConnectionFactory MariadbConnectionFactory MariadbConnectionConfiguration Create a new folder called "config" in , and create a new filed within it named "R2DBCConfig.java" /src/main/java/com/mariadb/todo Open "R2DBCConfig.java" and add the following code. com.mariadb.todo.config; org.mariadb.r2dbc.MariadbConnectionConfiguration; org.mariadb.r2dbc.MariadbConnectionFactory; org.mariadb.r2dbc.SslMode; org.springframework.context.annotation.Bean; org.springframework.context.annotation.Configuration; org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; java.io.IOException; java.io.InputStream; java.util.Properties; 2dbcRepositories { { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Properties props = Properties(); (InputStream f = loader.getResourceAsStream( )) { props.load(f); MariadbConnectionFactory(MariadbConnectionConfiguration.builder() .host(props.getProperty( )) .port(Integer.parseInt(props.getProperty( ))) .username(props.getProperty( )) .password(props.getProperty( )) .database(props.getProperty( )) .build()); } (IOException e) { System.out.println(e.getMessage()); ; } } } package import import import import import import import import import import @Configuration @EnableR public class R2DBCConfig extends AbstractR2dbcConfiguration @Override @Bean MariadbConnectionFactory public connectionFactory () new try "db.properties" return new "host" "port" "username" "password" "database" catch return null Notice that R2DBCConfig retrieves the database connection details from a file called "db.properties". To add the connection configuration navigate to , create a new file called "db.properties" and add the following code. /src/main/java/com/mariadb/resources host=127.0.0.1 port=3306 username=USERNAME_HERE password=PASSWORD_HERE database=todo Although not recommended you can add connection details directly to R2DBCConfig.java. Create a data service Services can be used to manage the business logic of your application. The only service, TasksService, in this application is used for validating a Task object and integrating with the TasksRepository. Create a new folder called "services" in , and create a new filed within it named "TasksService.java" /src/main/java/com/mariadb/todo Open "TasksService.java" and add the following code. com.mariadb.todo.services; com.mariadb.todo.models.Task; com.mariadb.todo.repositories.TasksRepository; org.springframework.beans.factory.annotation.Autowired; org.springframework.stereotype.Service; org.springframework.transaction.annotation.Transactional; reactor.core.publisher.Flux; reactor.core.publisher.Mono; { TasksRepository repository; { (task != && !task.getDescription().isEmpty()) { ; } ; } { .repository.findAll(); } { .repository.save(task); } { .repository.findById(task.getId()) .flatMap(t -> { t.setDescription(task.getDescription()); t.setCompleted(task.getCompleted()); .repository.save(t); }); } { .repository.findById(id) .flatMap( .repository::delete); } } package import import import import import import import // Registered as a Spring Service (Component) @Service public class TaskService // Automatically instantiate (via Spring IoC) @Autowired private // Boolean public isValid ( Task task) final if null return true return false // Get all records from the tasks table Flux<Task> public getAllTasks () return this // Save a new task record Mono<Task> public createTask ( Task task) final return this // Update an existing task record @Transactional Mono<Task> public updateTask ( Task task) final return this return this // Delete the task record by specified id @Transactional Mono<Void> public deleteTask ( id) final int return this this Expose API endpoints Finally, you'll need to create a controller to expose four endpoints that can be used to perform the basic CRUD operations on your Tasks. Create a new folder called "controllers" in , and create a new filed within it named "TasksController.java" /src/main/java/com/mariadb/todo Open "TasksController.java" and add the following code. com.mariadb.todo.controllers; com.mariadb.todo.models.Task; com.mariadb.todo.services.TaskService; org.springframework.beans.factory.annotation.Autowired; org.springframework.http.HttpStatus; org.springframework.http.ResponseEntity; org.springframework.web.bind.annotation.DeleteMapping; org.springframework.web.bind.annotation.GetMapping; org.springframework.web.bind.annotation.PostMapping; org.springframework.web.bind.annotation.PutMapping; org.springframework.web.bind.annotation.RequestBody; org.springframework.web.bind.annotation.RequestMapping; org.springframework.web.bind.annotation.RequestParam; org.springframework.web.bind.annotation.RestController; reactor.core.publisher.Flux; reactor.core.publisher.Mono; ( ) { TaskService service; () ResponseEntity<Flux<Task>> get() { ResponseEntity.ok( .service.getAllTasks()); } () ResponseEntity<Mono<Task>> post( Task task) { (service.isValid(task)) { ResponseEntity.ok( .service.createTask(task)); } ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).build(); } () ResponseEntity<Mono<Task>> put( Task task) { (service.isValid(task)) { ResponseEntity.ok( .service.updateTask(task)); } ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).build(); } () ResponseEntity<Mono<Void>> delete( id) { (id > ) { ResponseEntity.ok( .service.deleteTask(id)); } ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).build(); } } package import import import import import import import import import import import import import import import @RestController @RequestMapping "/api/tasks" public class TasksController @Autowired private @GetMapping public return this @PostMapping public @RequestBody if return this return @PutMapping public @RequestBody if return this return @DeleteMapping public @RequestParam int if 0 return this return Testing it out Now that everything has been constructed, it's time to test it out! First, build the application. $ mvn package And then run it. $ mvn spring-boot:run First, start by adding a new task to your to do list. $ curl --header \ --request POST \ --data '{ : }' \ http://localhost: /api/tasks "Content-Type: application/json" "description" "A New Task" 8080 While you can certainly query the database directly to confirm that a new task record has been added, where's the fun in that? Back to the API! $ curl https://localhost:8080/api/tasks If all goes well you should receive the following JSON response: { : , : , : } "id" 1 "description" "A New Task" "completed" false Voilà, a fully reactive Java Spring application using R2DBC and MariaDb! To view this code in its entirety check out the source . And if you're wondering "it'd sure be nice to see an implementation with a user interface", you're in luck! You can find a fully fleshed out implementation of a TODO application using React.js and your choice of multiple API projects (R2DBC, JDBC, Node.js and Python) that integrate directly with MariaDB ! here here Just getting started Now that you've successfully created a new Maven project using Spring Data, R2DBC and MariaDB, you have all the tools you need to get started creating fully reactive applications, utilizing the power of MariaDB, of your own! If you have any questions, suggestions or concerns with this blog post please let me know here or reach out to me directly on Twitter at ! @probablyrealrob Thanks for taking the time to read this and happy coding!