将 Spring Data R2DBC 用于 Azure SQL 数据库
本文演示如何通过使用 r2dbc-mssql GitHub 存储库中适用于 Microsoft SQL Server 的 R2DBC 实现创建一个示例应用程序,该应用程序使用 Spring Data R2DBC 在 Azure SQL 数据库中存储和检索信息。
R2DBC 将反应式 API 引入传统的关系数据库。 可以将它与 Spring WebFlux 配合使用,创建使用非阻止式 API 的完全响应式 Spring Boot 应用程序。 它提供的可伸缩性优于经典的“一个连接一个线程”方法。
先决条件
Azure 订阅 - 免费创建订阅。
Java 开发工具包(JDK)版本 8 或更高版本。
用来测试功能的 cURL 或类似的 HTTP 实用工具。
请参阅示例应用程序
在本文中,你将对示例应用程序进行编码。 如果希望加快进程,可通过 https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-sql-server 获得已编码的应用程序。
准备工作环境
首先,使用以下命令设置一些环境变量:
export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_SQL_SERVER_ADMIN_USERNAME=spring
export AZ_SQL_SERVER_ADMIN_PASSWORD=<YOUR_AZURE_SQL_ADMIN_PASSWORD>
export AZ_SQL_SERVER_NON_ADMIN_USERNAME=nonspring
export AZ_SQL_SERVER_NON_ADMIN_PASSWORD=<YOUR_AZURE_SQL_NON_ADMIN_PASSWORD>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
使用以下值替换占位符,在本文中将使用这些值:
<YOUR_DATABASE_NAME>
:Azure SQL 数据库服务器的名称,在 Azure 中应是唯一的。<YOUR_AZURE_REGION>
:将使用的 Azure 区域。 默认情况下可以使用eastus
,但我们建议你配置一个离居住位置更近的区域。 可以使用 查看可用区域az account list-locations
的完整列表。<AZ_SQL_SERVER_ADMIN_PASSWORD>
和<AZ_SQL_SERVER_NON_ADMIN_PASSWORD>
:Azure SQL 数据库服务器的密码,至少应包含 8 个字符。 这些字符应该属于以下类别中的三个类别:英文大写字母、英文小写字母、数字 (0-9)和非字母数字字符(!, $, #, % 等)。<YOUR_LOCAL_IP_ADDRESS>
:你将在其中运行 Spring Boot 应用程序的本地计算机的 IP 地址。 一种查看 IP 地址的便捷方法是打开 whatismyip.akamai.com。
接下来,请使用以下命令创建资源组:
az group create \
--name $AZ_RESOURCE_GROUP \
--location $AZ_LOCATION \
--output tsv
创建 Azure SQL 数据库实例
接下来,运行以下命令创建托管Azure SQL 数据库服务器实例。
注意
MS SQL 密码必须满足特定条件,并且安装程序会失败并显示不符合密码。 有关详细信息,请参阅 Password Policy。
az sql server create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_NAME \
--location $AZ_LOCATION \
--admin-user $AZ_SQL_SERVER_ADMIN_USERNAME \
--admin-password $AZ_SQL_SERVER_ADMIN_PASSWORD \
--output tsv
为 Azure SQL 数据库服务器配置防火墙规则
Azure SQL 数据库实例在默认情况下受保护。 它们有不允许任何传入连接的防火墙。 为了能够使用数据库,需要添加一项防火墙规则,允许本地 IP 地址访问数据库服务器。
由于我们已在本文开头配置了本地 IP 地址,因此你可通过运行以下命令来打开服务器的防火墙:
az sql server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_NAME-database-allow-local-ip \
--server $AZ_DATABASE_NAME \
--start-ip-address $AZ_LOCAL_IP_ADDRESS \
--end-ip-address $AZ_LOCAL_IP_ADDRESS \
--output tsv
如果要从 Windows 计算机上的 适用于 Linux 的 Windows 子系统 (WSL) 连接到 Azure SQL 数据库 服务器,则需要将 WSL 主机 ID 添加到防火墙。
通过在 WSL 中运行以下命令获取主机的 IP 地址:
cat /etc/resolv.conf
复制 nameserver
一词后面的 IP 地址,然后使用以下命令为 WSL IP 地址设置环境变量:
export AZ_WSL_IP_ADDRESS=<the-copied-IP-address>
然后使用以下命令向基于 WSL 的应用开放服务器的防火墙:
az sql server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_NAME-database-allow-local-ip-wsl \
--server $AZ_DATABASE_NAME \
--start-ip-address $AZ_WSL_IP_ADDRESS \
--end-ip-address $AZ_WSL_IP_ADDRESS \
--output tsv
配置 Azure SQL 数据库
你在前面创建的 Azure SQL 数据库服务器为空。 它没有任何可以与 Spring Boot 应用程序配合使用的数据库。 通过运行以下命令创建名为 demo
的新数据库:
az sql db create \
--resource-group $AZ_RESOURCE_GROUP \
--name demo \
--server $AZ_DATABASE_NAME \
--output tsv
创建 SQL 数据库非管理员用户并授予权限
此步骤将创建非管理员用户,并向该用户授予对数据库的所有权限 demo
。
创建一个名为 create_user.sql 的 SQL 脚本用于创建非管理员用户。 添加以下内容,在本地保存该脚本:
cat << EOF > create_user.sql
USE demo;
GO
CREATE USER $AZ_SQL_SERVER_NON_ADMIN_USERNAME WITH PASSWORD='$AZ_SQL_SERVER_NON_ADMIN_PASSWORD'
GO
GRANT CONTROL ON DATABASE::demo TO $AZ_SQL_SERVER_NON_ADMIN_USERNAME;
GO
EOF
然后,使用以下命令运行 SQL 脚本以创建非管理员用户:
sqlcmd -S $AZ_DATABASE_NAME.database.windows.net,1433 -d demo -U $AZ_SQL_SERVER_ADMIN_USERNAME -P $AZ_SQL_SERVER_ADMIN_PASSWORD -i create_user.sql
注意
有关创建 SQL 数据库用户的详细信息,请参阅 CREATE U标准版R (Transact-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 -
添加响应式 Azure SQL 数据库驱动程序实现
打开所生成项目的 pom.xml 文件,以添加来自 r2dbc-mssql GitHub 存储库的响应式 Azure SQL 数据库驱动程序。
在 spring-boot-starter-webflux
依赖项后,添加以下文本:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-mssql</artifactId>
<scope>runtime</scope>
</dependency>
将 Spring Boot 配置为使用 Azure SQL 数据库
打开 src/main/resources/application.properties 文件,添加以下文本:
logging.level.org.springframework.data.r2dbc=DEBUG
spring.r2dbc.url=r2dbc:pool:mssql://$AZ_DATABASE_NAME.database.windows.net:1433/demo
spring.r2dbc.username=nonspring@$AZ_DATABASE_NAME
spring.r2dbc.password=$AZ_SQL_SERVER_NON_ADMIN_PASSWORD
将这两个 $AZ_DATABASE_NAME
变量和 $AZ_SQL_SERVER_NON_ADMIN_PASSWORD
变量替换为在本文开头部分配置的值。
注意
为了提高性能,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 INT IDENTITY PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BIT);
停止正在运行的应用程序并使用以下命令重启。 现在,该应用程序将使用之前创建的 demo
数据库,并在其中创建一个 todo
表。
./mvnw spring-boot:run
下面是正在创建的数据库表的屏幕截图:
编写应用程序代码
接下来添加 Java 代码,以便使用 R2DBC 在 Azure SQL 数据库服务器中存储和检索数据。
使用以下代码,在 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 SQL 数据库中存储和检索数据。
清理资源
若要清理本快速入门期间使用的所有资源,请使用以下命令删除资源组:
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。