6

robincakeellis/sqlrx: 使用Spring Boot的反应式MySQL

 1 year ago
source link: https://www.jdon.com/61277
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用Spring Boot的反应式MySQL
这是一个使用 Spring Boot 和 R2DBC 从 MySQL 8 数据库响应式返回数据的工作 Java 项目。可配置应用程序属性和构建时测试。

Github 项目中有一个包含测试数据的简单 SQL 脚本。最后是完整静态数据的各种风格的链接。
技术栈

  • Java:我正在使用 OpenJDK 17。我还使用 OpenJDK 8 构建和运行,一切都很好。
  • Spring Boot:我使用的是 2.7.x。我还用 2.5.0 构建和运行,没问题。
  • MySQL 8:我将它与 MySQL Workbench 一起安装。我没有使用 MySQL 5 进行测试,也没有使用 Docker 容器。
  • R2DBC:SQL 数据库的反应式网关。它包含在 Spring Boot 中。
  • Junit:我使用的是 v5,但 v4 应该可以正常工作,可能带有温和的注释编辑。
  • Apache Maven:我用 Maven 组装。我没有用 Gradle 进行测试。

POM文件说明:
对程序集 POM 的回顾:其中有什么,没有什么。该列表适用于 Gradle。

  • Java 版本在此处指定。请记住将其从 17 编辑为适合您的任何版本。同样,将 Spring Boot 版本指定为父版本。
  • spring-boot-starter-webflux将给出 Mono、Flux 和通常的控制器注释。
  • spring-boot-starter-data-r2dbc将在对数据库的响应式调用前面。
  • dev.miku:r2dbc-mysql是位于 R2DBC 和 MySQL 之间的驱动程序。MySQL 的另一个选择是com.github.jasync-sql:jasync-r2dbc-msqyl,对于 H2 等其他数据库,您可以查看最后的链接。
  • spring-boot-starter-test用于检测。
  • io.projectreactor:reactor:test用于测试反应结果。

我的可选依赖项是 Lombok 和 Spring Boot Devtools,它们不是必需的,但我认为它们很好。

POM中没有的内容:

  • spring-boot-starter-web: 不必要。Webflux 提供了所需的东西。
  • 任何与 JPA 或 JDBC 相关的内容:不。我不会启用 JPA 存储库,也不需要 JDBC。
  • mysql-connector-java: 不。这对于反应性工作是不需要的。它甚至不是传递依赖。松手。
  • 任何东西 HikariCP:没有。R2DBC 有自己的连接池。
  • 任何与 Tomcat、Jetty 或 Undertow 相关的东西:不。Netty 支持响应式工作。可能可以使用替代方法,但这超出了本文的范围。

基本项目将具有 POM、带有空 application.properties(或 .yaml)的典型文件夹结构和两个类:

  • 主源代码中的第一个类是基本的 Spring Boot 应用程序启动器。它将有一个静态的 main 方法,以及@SpringBootApplication类上的单个注释
  • 测试源中的第二个类是应用程序启动测试。它将有一个方法 - 可能称为 contextLoads() - 带有注释,@Test并且类本身也带有注释@SpringBootTest

数据访问 - Bean
Hibernate强大的用户可能已经经历过表名被重命名以适应平台的情况。例如,使用MySQL时,agtAgents会被Hibernate重命名为agt_types。这种情况在R2DBC中不会发生--你在@Table中指定的内容就是你在查询中得到的内容。

尽管如此(!),如果你没有指定名称,那么就会应用一个策略。例如,Bean被称为AgentRow,所以--如果没有特定的表名--R2DBC会尝试使用agent_row作为表名。

Bean中的属性将被映射到表中的匹配列。这种情况对你的SQL提供者来说可能很重要,也可能不重要,所以你可以指定一个确切的列名来使用每个属性。例如,我有一个名为agentTypeId的bean属性,它被映射到列agentTypeID,我有一个名为locator的bean布尔值,它被映射到列isLocator。

主键是使用@Id来记录的。我没有使用R2DBC的复合主键的经验。

数据访问 - 属性
我需要指定我的数据所在的位置,所以是时候更新application.properties(或.yaml)了。关键属性是spring.r2dbc.url和spring.r2dbc.username和spring.r2dbc.password。

标准的spring.datasource.*属性与R2DBC无关。使用spring.r2dbc.* - 全套已知的属性可能会出现在你的IDE的自动完成中,或者你可以在大量的Spring Boot属性页面上找到它们(在最后链接)。

一个重要的变化是,你必须从jdbc: 前缀的URLs转移到r2dbc。

池化是默认启用的,但我相信你需要在连接URL中指定:pool,以实际使用连接池。我愿意接受纠正!

一个R2DBC的URL:spring.r2dbc.url=r2dbc:pool:mysql://localhost:3306/SQL_RX_TEST?zeroDateTimeBehavior=convertToNull&useSSL=false&useServerPrepareStatement=true

请记住,Hibernate相关的属性或HikariCP配置不需要在你的属性文件上。

服务
我需要一个服务来隐藏所有未使用的 repo 功能。服务方法可以进行一些转换或装饰,但对于这个项目,服务是一个代理。任何来自repo的Flux或Mono都会按原样返回给服务调用者。

我可以为服务写测试,但由于它是一个代理,我跳过了这些测试。令人震惊。

控制器
控制器端点有典型的映射相关注解。控制器调用服务,并以服务返回的任何内容回应调用者--一直是反应式的。

@GetMapping("/corp/{id}")
public Flux<AgentRow> getForCorp(@PathVariable int id) {
    return service.getForCorp(id);
}

如果你用@Controller来注解你的控制器,可能会出现一个问题:调用一个反应式端点可能会导致一个异常,如视图解析中不支持多值反应式类型。这个问题可以通过在方法上标注@ResponseBody来解决。或者,用@RestController来注解控制器。

我想测试一下这个控制器。非反应式的方法是用@WebMvcTest来注解测试类,在MockMvc实例中布线,模拟底层实例(如服务),调用控制器,用jsonPath()检查响应,包括内容。

我们不知道数据何时会到达ReactiveLand,所以我们遵循不同的路线。

我使用@WebFluxText(而不是WebMvcTest)并指定我正在测试的控制器类。我连接了一个WebTestClient(而不是MockMvc)。我仍然需要向模拟的服务提供数据,以便端点能够找到一些东西。我可以使用Web测试客户端调用端点并测试响应。

我学到的一个很酷的东西是,你可以检查响应的状态和头信息,然后将主体传递给StepVerifier,以进行彻底的反应式测试。

final ResponseSpec response = webTestClient
   .get().uri("http://localhost:8080/agents/ids")
   .exchange();
final Flux<Integer> flux = response
   .expectStatus().isOk()
   .returnResult(Integer.class)
   .getResponseBody();
StepVerifier.create(flux.collectList())
   .expectNextMatches(list -> list.size() == 2)
   .verifyComplete();

 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK