Использование Spring Data R2DBC с базой данных Azure SQL

В этой статье показано, как создать пример приложения, использующего Spring Data R2DBC для хранения и получения информации в База данных SQL Azure с помощью реализации R2DBC для Microsoft SQL Server из репозитория GitHub r2dbc-mssql.

R2DBC приносит реактивные API к традиционным реляционным базам данных. Вы можете применять это решение со Spring WebFlux для создания полностью реактивных приложений Spring Boot, которые используют неблокирующие API. Оно обеспечивает улучшенную масштабируемость по сравнению с классическим подходом "один поток на подключение".

Предварительные требования

  • Утилита sqlcmd.

  • 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>: Имя сервера База данных SQL Azure, которое должно быть уникальным в Azure.
  • <YOUR_AZURE_REGION>: регион Azure, который вы будете использовать. Вы можете использовать eastus по умолчанию, но настроить регион ближе к месту жизни. Полный список доступных регионов можно посмотреть с помощью az account list-locations.
  • <AZ_SQL_SERVER_ADMIN_PASSWORD>и <AZ_SQL_SERVER_NON_ADMIN_PASSWORD>: пароль База данных SQL Azure сервера, который должен содержать не менее восьми символов. и включать знаки всех следующих типов: прописные латинские буквы, строчные латинские буквы, цифры (0–9) и небуквенно-цифровые знаки (!, $, #, % и т. д.).
  • <YOUR_LOCAL_IP_ADDRESS>: IP-адрес локального компьютера, с которого будет запущено приложение Spring Boot. Один из удобных способов найти его — открыть whatismyip.akamai.com.

Примечание.

Корпорация Майкрософт рекомендует использовать самый безопасный поток проверки подлинности. Поток проверки подлинности, описанный в этой процедуре, например для баз данных, кэшей, сообщений или служб ИИ, требует очень высокой степени доверия к приложению и несет риски, не присутствующих в других потоках. Используйте этот способ только в том случае, если более безопасные варианты, такие как управляемые удостоверения для подключений без пароля или без ключей, не подходят. Для операций на локальном компьютере предпочтительнее использовать учетные данные пользователя для подключений без пароля или без ключа.

Чтобы создать группу ресурсов, выполните следующую команду:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    --output tsv

Создание экземпляра Базы данных SQL Azure

Затем создайте управляемый экземпляр сервера База данных SQL Azure, выполнив следующую команду.

Примечание.

Пароль MS SQL должен соответствовать определённым требованиям, и установка завершается ошибкой, если пароль им не соответствует. Дополнительные сведения см. в разделе Политика паролей.

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

Настройка правила брандмауэра для сервера Базы данных SQL Azure

Экземпляры Базы данных SQL Azure по умолчанию защищены. В них включен брандмауэр, который блокирует все входящие подключения. Чтобы использовать базу данных, необходимо добавить правило брандмауэра, позволяющее локальному 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

Если вы подключаетесь к серверу База данных SQL Azure из подсистема Windows для Linux (WSL) на компьютере Windows, необходимо добавить идентификатор узла WSL в брандмауэр.

Получите IP-адрес хост-компьютера, выполнив следующую команду в WSL:

cat /etc/resolv.conf

Скопируйте IP-адрес, следующий за термином nameserver, а затем используйте следующую команду, чтобы задать переменную среды для IP-адреса WSL:

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

Настройка базы данных SQL Azure

Сервер Базы данных SQL Azure, который вы создали ранее, сейчас пустой. На нем отсутствует база данных, которую можно использовать с приложением Spring Boot. Создайте базу данных с именем demo, выполнив следующую команду:

az sql db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name demo \
    --server $AZ_DATABASE_NAME \
    --output tsv

Создание пользователя, отличного от администратора базы данных SQL, и предоставление разрешения

На этом шаге вы создаёте пользователя без прав администратора и предоставляете этому пользователю все разрешения на базу данных demo.

Создайте скрипт SQL с именем create_user.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 USER (Transact-SQL).


Создание реактивного приложения Spring Boot

Чтобы создать реактивное приложение Spring Boot, мы будем использовать Spring Initializr. Приложение, которое мы создадим, использует:

  • Spring Boot 2.7.11.
  • Следующие зависимости: Spring Reactive 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 -

Добавление реализации реактивного драйвера Базы данных SQL Azure

Откройте файл pom.xml в созданном проекте, чтобы добавить реактивный драйвер Базы данных SQL Azure из репозитория GitHub r2dbc-mssql.

После зависимости spring-boot-starter-webflux добавьте следующий текст:

<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-mssql</artifactId>
    <scope>runtime</scope>
</dependency>

Настройка Spring Boot для использования Базы данных SQL Azure

Откройте файл 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 настройте новый bean-компонент Spring, который создаст схему базы данных, с помощью следующего кода:

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;
    }
}

Этот bean-компонент Spring использует файл с именем 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 для хранения и извлечения данных с сервера База данных SQL Azure.

Создайте новый класс Java Todo рядом с классом DemoApplication с помощью следующего кода:

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.

Сначала создайте новый элемент todo в базе данных с помощью следующей команды:

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

Эта команда вернет список элементов todo, включая созданный вами элемент, как показано здесь:

[{"id":1,"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done":true}]

Ниже приведен снимок экрана с этими запросами cURL:

Снимок экрана: тест cURL.

Поздравляем! Вы создали полностью реактивное приложение Spring Boot, которое использует R2DBC для хранения и получения данных из База данных SQL Azure.

Очистка ресурсов

Чтобы удалить все ресурсы, использованные в этом кратком руководстве, удалите группу ресурсов с помощью следующей команды:

az group delete \
    --name $AZ_RESOURCE_GROUP \
    --yes

Следующие шаги

Дополнительные сведения о развертывании приложения Spring Data в Приложения Azure Spring и использовании управляемого удостоверения см. в руководстве по развертыванию приложения Spring в Приложения Azure Spring с подключением без пароля к базе данных Azure.

Дополнительные сведения о Spring и Azure см. в центре документации об использовании Spring в Azure.

См. также

См. сведения о Spring Data R2DBC в справочной документации по Spring.

Дополнительные сведения об использовании Azure с Java см. в статьях Azure для разработчиков Java и Работа с Azure DevOps и Java.