如何使用R2DBC连接数据库?

一、R2DBC是什么?

反应式编程能大大降低服务器的内存和线程需要量。但是并非所有数据库都能原生支持反应式编程。通常只有非关系型数据库支持反应式编程。为了使关系型数据库支持反应式编程,发明了R2DBC。

二、如何使用R2DBC

1. 使用Maven引入的依赖项

部分pom.xml

...
  <dependencies>
    <!-- Spring WebFlux依赖项 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <!-- Spring Data JPA依赖项 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- H2嵌入式数据库依赖项 -->
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
    </dependency>
    <!-- R2DBC依赖项,用于使不支持反应式的数据库支持反应式 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-r2dbc</artifactId>
    </dependency>
    <!-- R2DBC-h2依赖项,为了使R2DBC能使用H2数据库 -->
    <dependency>
      <groupId>io.r2dbc</groupId>
      <artifactId>r2dbc-h2</artifactId>
      <scope>runtime</scope>
    </dependency>
    <!-- lombok依赖项,用于自动生成代码 -->
	<dependency>
	  <groupId>org.projectlombok</groupId>
	  <artifactId>lombok</artifactId>
	  <optional>true</optional>
	</dependency>
  </dependencies>
...

2. 配置文件

application.yml

spring: 
  r2dbc: 
    # 设置R2DBC的url。这里使用的h2数据库。基于内存。创建的数据库名是testdb
    url: r2dbc:h2:mem://./testdb
    username: sa
    password: 123456

3. Java文件

Usr.java

package model;

import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import lombok.AllArgsConstructor;
import lombok.Data;

@Table
@Data
@AllArgsConstructor
public class Usr {
	@Id
	private Integer id;
	private String firstname;
	private String lastname;
	
	boolean hasId() {
		return id != null;
	}
}

UsrRepository.java

package repository;

import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
import model.Usr;

public interface UsrRepository extends ReactiveCrudRepository<Usr, Integer> {
	@Query("SELECT id, firstname, lastname FROM Usr c WHERE c.lastname = :lastname")
	Flux<Usr> findByLastname(String lastname);
}

UsrController.java

package controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import model.Usr;
import repository.UsrRepository;

@RestController
@RequestMapping(path = "/user", produces = "application/hal+json")
@RequiredArgsConstructor
public class UsrController {
	private final UsrRepository usrRepository;
	
	@GetMapping("/all")
	public Flux<Usr> findAll() {
		return usrRepository.findAll();
	}
	
	@GetMapping("/save")
	public Mono<Usr> save() {
		Usr user = new Usr(null, "Lindong", "Wang");
		return usrRepository.save(user);
	}
}

DatabaseConfig.java

package config;

import java.util.Arrays;
import java.util.List;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.r2dbc.core.DatabaseClient;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import model.Usr;
import repository.UsrRepository;

@Configuration
@Slf4j
public class DbConfig {
	@Bean
	public ApplicationRunner initDatabase(DatabaseClient client, UsrRepository usrRepository) {
		List<String> statements = Arrays.asList(
				"DROP TABLE IF EXISTS Usr;", 
				"CREATE TABLE IF NOT EXISTS Usr (id SERIAL PRIMARY KEY, firstname VARCHAR(100) NOT NULL, lastname VARCHAR(100) NOT NULL);");
		statements.forEach(sql -> executeSql(client, sql)
				.doOnSuccess(count -> log.info("Schema created, rows updated: {}", count))
				.doOnError(error -> log.error("got error: {}", error.getMessage(), error))
				.subscribe()
		);
		return args -> getUser().flatMap(usrRepository::save).subscribe(user -> log.info("User saved: {}", user));
	}
	
	private Flux<Usr> getUser() {
		return Flux.just(new Usr(null, "John", "Doe"), new Usr(null, "Jane", "Doe"));
	}
	
	private Mono<Integer> executeSql(DatabaseClient client, String sql) {
		return client.sql(sql).fetch().rowsUpdated();
	}
}

4. 测试代码

在控制台输入:curl localhost:8080/user/all
可以获得返回结果:[{“id”:1,“firstname”:“John”,“lastname”:“Doe”},{“id”:2,“firstname”:“Jane”,“lastname”:“Doe”}]

上一篇:Java 响应式关系数据库连接了解一下


下一篇:cybox靶机渗透测试