将 Spring Data R2DBC 与 Azure Database for PostgreSQL 配合使用
本文演示如何创建示例应用程序,使其使用 Spring Data R2DBC 在 Azure Database for PostgreSQL 数据库中存储和检索信息。 该示例从 GitHub 上 r2dbc-postgresql 存储库中使用 PostgreSQL 的 R2DBC 实现。
R2DBC 将反应式 API 引入传统的关系数据库。 可以将它与 Spring WebFlux 配合使用,创建使用非阻止式 API 的完全响应式 Spring Boot 应用程序。 它提供的可伸缩性优于经典的“一个连接一个线程”方法。
先决条件
Azure 订阅 - 免费创建订阅。
Java 开发工具包 (JDK) 版本 8 或更高版本。
用来测试功能的 cURL 或类似的 HTTP 实用工具。
请参阅示例应用程序
在本文中,你将编写一个示例应用程序。 如果希望加快进程,可通过 https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-postgresql 获得已编码的应用程序。
准备工作环境
首先,通过运行以下命令来设置一些环境变量:
export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_POSTGRESQL_ADMIN_USERNAME=spring
export AZ_POSTGRESQL_ADMIN_PASSWORD=<YOUR_POSTGRESQL_ADMIN_PASSWORD>
export AZ_POSTGRESQL_NON_ADMIN_USERNAME=nonspring
export AZ_POSTGRESQL_NON_ADMIN_PASSWORD=<YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
使用以下值替换占位符,在本文中将使用这些值:
<YOUR_DATABASE_SERVER_NAME>
:PostgreSQL 服务器的名称,应在整个 Azure 中保持唯一。<YOUR_DATABASE_NAME>
:PostgreSQL 服务器的数据库名称,该名称在 Azure 中应是唯一的。<YOUR_AZURE_REGION>
:将使用的 Azure 区域。 默认情况下可以使用eastus
,但我们建议你配置一个离居住位置更近的区域。 可以使用 查看可用区域az account list-locations
的完整列表。<YOUR_POSTGRESQL_ADMIN_PASSWORD>
和<YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>
:PostgreSQL 数据库服务器的密码,该服务器至少应包含 8 个字符。 这些字符应该属于以下类别中的三个类别:英文大写字母、英文小写字母、数字 (0-9)和非字母数字字符(!, $, #, % 等)。<YOUR_LOCAL_IP_ADDRESS>
:你将在其中运行 Spring Boot 应用程序的本地计算机的 IP 地址。 一种查看 IP 地址的便捷方法是打开 whatismyip.akamai.com。
注意
Microsoft 建议使用最安全的可用身份验证流。 此过程中所述的身份验证流(例如数据库、缓存、消息传送或 AI 服务)需要高度信任应用程序,并且存在其他流中不存在的风险。 仅当更安全的选项(例如无密码连接或无密钥连接的托管标识)不可行时,才使用此流。 对于本地计算机操作,首选无密码连接或无密钥连接的用户标识。
接下来,请使用以下命令创建资源组:
az group create \
--name $AZ_RESOURCE_GROUP \
--location $AZ_LOCATION \
--output tsv
创建 Azure Database for PostgreSQL 实例并设置管理员用户
首先需要创建具有管理员用户的托管 PostgreSQL 服务器。
注意
可以在使用 Azure 门户创建 Azure Database for PostgreSQL 服务器中阅读有关创建 PostgreSQL 服务器的更多详细信息。
az postgres flexible-server create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--location $AZ_LOCATION \
--admin-user $AZ_POSTGRESQL_ADMIN_USERNAME \
--admin-password $AZ_POSTGRESQL_ADMIN_PASSWORD \
--yes \
--output tsv
配置 PostgreSQL 数据库
你在前面创建的 PostgreSQL 服务器为空。 使用以下命令创建新数据库。
az postgres flexible-server db create \
--resource-group $AZ_RESOURCE_GROUP \
--database-name $AZ_DATABASE_NAME \
--server-name $AZ_DATABASE_SERVER_NAME \
--output tsv
为 PostgreSQL 服务器配置防火墙规则
Azure Database for PostgreSQL 实例在默认情况下受保护。 它们有不允许任何传入连接的防火墙。 为了能够使用数据库,需要添加一项防火墙规则,允许本地 IP 地址访问数据库服务器。
由于我们已在本文开头配置了本地 IP 地址,因此你可通过运行以下命令来打开服务器的防火墙:
az postgres flexible-server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
--start-ip-address $AZ_LOCAL_IP_ADDRESS \
--end-ip-address $AZ_LOCAL_IP_ADDRESS \
--output tsv
如果要在 Windows 计算机上从适用于 Linux 的 Windows 子系统连接到 PostgreSQL 服务器,则需要将 WSL 主机 ID 添加到防火墙。
通过在 WSL 中运行以下命令获取主机的 IP 地址:
cat /etc/resolv.conf
复制 nameserver
一词后面的 IP 地址,然后使用以下命令为 WSL IP 地址设置环境变量:
export AZ_WSL_IP_ADDRESS=<the-copied-IP-address>
然后使用以下命令向基于 WSL 的应用开放服务器的防火墙:
az postgres flexible-server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
--start-ip-address $AZ_WSL_IP_ADDRESS \
--end-ip-address $AZ_WSL_IP_ADDRESS \
--output tsv
创建 PostgreSQL 非管理员用户并授予权限
接下来创建一个非管理员用户,并为其授予对数据库的所有权限。
注意
可以阅读在 Azure Database for PostgreSQL 中创建用户来获取有关创建 PostgreSQL 用户的更详细信息。
创建一个名为 create_user.sql 的 SQL 脚本用于创建非管理员用户。 添加以下内容,在本地保存该脚本:
注意
Microsoft 建议使用最安全的可用身份验证流。 此过程中所述的身份验证流(例如数据库、缓存、消息传送或 AI 服务)需要高度信任应用程序,并且存在其他流中不存在的风险。 仅当更安全的选项(例如无密码连接或无密钥连接的托管标识)不可行时,才使用此流。 对于本地计算机操作,首选无密码连接或无密钥连接的用户标识。
cat << EOF > create_user.sql
CREATE ROLE "$AZ_POSTGRESQL_NON_ADMIN_USERNAME" WITH LOGIN PASSWORD '$AZ_POSTGRESQL_NON_ADMIN_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE $AZ_DATABASE_NAME TO "$AZ_POSTGRESQL_NON_ADMIN_USERNAME";
EOF
然后,使用以下命令运行该 SQL 脚本以创建 Microsoft Entra 非管理员用户:
psql "host=$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com user=$AZ_POSTGRESQL_ADMIN_USERNAME dbname=$AZ_DATABASE_NAME port=5432 password=$AZ_POSTGRESQL_ADMIN_PASSWORD sslmode=require" < create_user.sql
现在使用以下命令删除临时 SQL 脚本文件:
rm create_user.sql
创建反应式 Spring Boot 应用程序
若要创建一个响应式 Spring Boot 应用程序,可使用 Spring Initializr。 要创建的应用程序使用:
- Spring Boot 2.7.11。
- 以下依赖项:Spring 反应 Web(也称为 Spring WebFlux)和 Spring Data R2DBC。
使用 Spring Initializr 生成应用程序
使用以下命令在命令行上生成应用程序:
curl https://start.spring.io/starter.tgz -d dependencies=webflux,data-r2dbc -d baseDir=azure-database-workshop -d bootVersion=2.7.11 -d javaVersion=17 | tar -xzvf -
添加响应式 PostgreSQL 驱动程序实现
打开所生成项目的 pom.xml 文件,然后添加来自 GitHub 上 r2dbc-postgresql 存储库的响应式 PostgreSQL 驱动程序。 在 spring-boot-starter-webflux
依赖项后,添加以下文本:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<version>0.8.12.RELEASE</version>
<scope>runtime</scope>
</dependency>
将 Spring Boot 配置为使用 Azure Database for PostgreSQL
打开 src/main/resources/application.properties 文件,添加以下文本:
logging.level.org.springframework.data.r2dbc=DEBUG
spring.r2dbc.url=r2dbc:pool:postgres://$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com:5432/$AZ_DATABASE_NAME
spring.r2dbc.username=nonspring
spring.r2dbc.password=$AZ_POSTGRESQL_NON_ADMIN_PASSWORD
spring.r2dbc.properties.sslMode=REQUIRE
将 $AZ_DATABASE_SERVER_NAME
变量 $AZ_DATABASE_NAME
和 $AZ_POSTGRESQL_NON_ADMIN_PASSWORD
变量替换为本文开头配置的值。
警告
出于安全原因,Azure Database for PostgreSQL 要求使用 SSL 连接。 这就是你需要添加 spring.r2dbc.properties.sslMode=REQUIRE
配置属性的原因,否则,R2DBC PostgreSQL 驱动程序将尝试使用不安全的连接进行连接,而这将会失败。
注意
为了提高性能,spring.r2dbc.url
属性配置为通过 r2dbc-pool 使用连接池。
现在,你应能够使用提供的 Maven 包装器启动应用程序,如下所示:
./mvnw spring-boot:run
下面是首次运行的应用程序的屏幕截图:
创建数据库架构
在主 DemoApplication
类中使用以下代码配置新的 Spring Bean,它将创建数据库架构:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.r2dbc.connectionfactory.init.ConnectionFactoryInitializer;
import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator;
import io.r2dbc.spi.ConnectionFactory;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(new ClassPathResource("schema.sql"));
initializer.setDatabasePopulator(populator);
return initializer;
}
}
此 Spring Bean 使用名为“schema.sql”的文件,因此请在“src/main/resources”文件夹中创建该文件并添加以下文本:
DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);
停止正在运行的应用程序并使用以下命令重启。 现在,该应用程序将使用之前创建的 demo
数据库,并在其中创建一个 todo
表。
./mvnw spring-boot:run
下面是正在创建的数据库表的屏幕截图:
编写应用程序代码
接下来添加 Java 代码,以便使用 R2DBC 在 PostgreSQL 服务器中存储和检索数据。
使用以下代码,在 DemoApplication
类旁创建一个新的 Todo
Java 类:
package com.example.demo;
import org.springframework.data.annotation.Id;
public class Todo {
public Todo() {
}
public Todo(String description, String details, boolean done) {
this.description = description;
this.details = details;
this.done = done;
}
@Id
private Long id;
private String description;
private String details;
private boolean done;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
public boolean isDone() {
return done;
}
public void setDone(boolean done) {
this.done = done;
}
}
此类是映射在之前创建的 todo
表上的域模型。
若要管理该类,需要一个存储库。 使用以下代码,在同一包中定义一个新的 TodoRepository
接口:
package com.example.demo;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface TodoRepository extends ReactiveCrudRepository<Todo, Long> {
}
此存储库是 Spring Data R2DBC 管理的响应式存储库。
创建可存储和检索数据的控制器,完成该应用程序。 在同一包中实现 TodoController
类,并添加以下代码:
package com.example.demo;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/")
public class TodoController {
private final TodoRepository todoRepository;
public TodoController(TodoRepository todoRepository) {
this.todoRepository = todoRepository;
}
@PostMapping("/")
@ResponseStatus(HttpStatus.CREATED)
public Mono<Todo> createTodo(@RequestBody Todo todo) {
return todoRepository.save(todo);
}
@GetMapping("/")
public Flux<Todo> getTodos() {
return todoRepository.findAll();
}
}
最后,使用以下命令暂停应用程序并再次启动它:
./mvnw spring-boot:run
测试应用程序
若要测试应用程序,可使用 cURL。
首先,使用以下命令在数据库中创建一个新的待办事项:
curl --header "Content-Type: application/json" \
--request POST \
--data '{"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done": "true"}' \
http://127.0.0.1:8080
此命令应返回创建的项,如下所示:
{"id":1,"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done":true}
接下来,通过以下命令使用新的 cURL 请求来检索数据:
curl http://127.0.0.1:8080
此命令将返回待办事项列表,其中包括已创建的项,如下所示:
[{"id":1,"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done":true}]
下面是这些 cURL 请求的屏幕截图:
祝贺你! 你已创建了一个完全响应式 Spring Boot 应用程序,该应用程序使用 R2DBC 在 Azure Database for PostgreSQL 中存储和检索数据。
清理资源
若要清理本快速入门期间使用的所有资源,请使用以下命令删除资源组:
az group delete \
--name $AZ_RESOURCE_GROUP \
--yes
后续步骤
若要详细了解如何将 Spring Data 应用程序部署到 Azure Spring Apps 并使用托管标识,请参阅 教程:使用与 Azure 数据库的无密码连接将 Spring 应用程序部署到 Azure Spring Apps。
若要了解有关 Spring 和 Azure 的详细信息,请继续访问“Azure 上的 Spring”文档中心。
另请参阅
有关 Spring Data R2DBC 的详细信息,请参阅 Spring 的参考文档。
若要详细了解如何将 Azure 与 Java 配合使用,请参阅面向 Java 开发人员的 Azure 和使用 Azure DevOps 和 Java。