Mình đã giới thiệu với các bạn về Reactive Relational Database Connectivity (R2DBC) specs, về bộ thư viện Service Provider Interface và các driver implement cho bộ thư viện SPI này trong bài viết trước. Nếu ứng dụng của các bạn sử dụng Spring framework và muốn thao tác với database theo cơ chế reactive, các bạn có thể sử dụng Spring Data R2DBC để việc thao tác với database thuận tiện và dễ dàng hơn. Cụ thể như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!
Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:
Mình sẽ sử dụng PostgreSQL database để làm ví dụ nên mình sẽ khai báo PostgreSQL R2DBC driver và Spring Data R2DBC dependency như sau:
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-r2dbc</artifactId> <version>3.1.1</version> </dependency> <dependency> <groupId>io.r2dbc</groupId> <artifactId>r2dbc-postgresql</artifactId> <version>0.8.13.RELEASE</version> </dependency> |
Trong bài viết trước, mình đã đề cập đến đối tượng của class ConnectionFactory để khai báo thông tin kết nối tới database server, ở đây là PostgreSQL database. Với Spring Data R2DBC thì các bạn cũng cần khởi tạo đối tượng của class ConnectionFactory này, dưới dạng là một bean trong Spring container.
Spring Data R2DBC cung cấp cho chúng ta một abstract class tên là AbstractR2dbcConfiguration để cấu hình các bean cần thiết để chúng ta làm việc với database theo cơ chế reactive.
Trong class AbstractR2dbcConfiguration này, các bạn sẽ thấy nó định nghĩa một abstract method để tạo mới đối tượng của class ConnectionFactory. Các bạn cần tạo mới một class extends class AbstractR2dbcConfiguration này để định nghĩa bean cho class ConnectionFactory nhé! Ví dụ của mình như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.huongdanjava.springdatar2dbc; import io.r2dbc.spi.ConnectionFactories; import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration; import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories; @Configuration @EnableR2dbcRepositories public class DatabaseConfiguration extends AbstractR2dbcConfiguration { @Bean public ConnectionFactory connectionFactory() { ConnectionFactoryOptions options = ConnectionFactoryOptions.builder() .option(ConnectionFactoryOptions.DRIVER, "postgresql") .option(ConnectionFactoryOptions.HOST, "localhost") .option(ConnectionFactoryOptions.USER, "khanh") .option(ConnectionFactoryOptions.PASSWORD, "123456") .option(ConnectionFactoryOptions.DATABASE, "spring_data_r2dbc_example") .build(); return ConnectionFactories.get(options); } } |
Như các bạn thấy, ở đây mình cũng khai báo sử dụng annotation @EnableR2dbcRepositories. Mục đích của annotation này, tương tự như annotation @EnableJpaRepositories trong Spring Data JPA, nó sẽ giúp cho Spring tự động scan và khởi tạo bean cho các class Repository của Spring Data R2DBC. Annotation @EnableR2dbcRepositories cho phép chúng ta cấu hình package để scan với thuộc tính basePackages hoặc basePackageClasses, nếu các bạn không khai báo các thuộc tính này thì mặc định Spring sẽ scan package chứa class được annotated với annotation @EnableR2dbcRepositories các bạn nhé!
Tiếp theo, chúng ta sẽ định nghĩa các class Repository liên quan đến ứng dụng.
Để làm ví dụ, mình sẽ định nghĩa table “student”:
1 2 3 4 5 |
CREATE TABLE student ( id INT NOT NULL, name VARCHAR(50) DEFAULT NULL, PRIMARY KEY (id) ) |
với nội dung như sau trong PostgreSQL database:
Class model cho table “student”, mình sẽ định nghĩa như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.huongdanjava.springdatar2dbc; import org.springframework.data.annotation.Id; import org.springframework.data.relational.core.mapping.Table; @Table public class Student { private static final long serialVersionUID = 1L; @Id private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } |
Tương tự như Spring Data JPA, các bạn có thể định nghĩa class Repository với Spring Data R2DBC cho table “student” như sau:
1 2 3 4 5 6 7 8 9 |
package com.huongdanjava.springdatar2dbc; import org.springframework.data.r2dbc.repository.R2dbcRepository; import org.springframework.stereotype.Repository; @Repository public interface StudentRepository extends R2dbcRepository<Student, Long> { } |
Đến đây thì chúng ta đã cấu hình xong Spring Data R2DBC cho ứng dụng của mình rồi đó các bạn!
Để kiểm tra kết quả, mình sẽ viết một class với main() method có nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.huongdanjava.springdatar2dbc; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Application { public static void main(String[] args) throws InterruptedException { ApplicationContext ac = new AnnotationConfigApplicationContext(DatabaseConfiguration.class); StudentRepository studentRepository = (StudentRepository) ac.getBean("studentRepository"); studentRepository.findAll().log() .map(s -> { System.out.println(s.getName()); return s; }) .subscribe(); Thread.sleep(10000); } } |
Kết quả khi chúng ta chạy ví dụ trên như sau: