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

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

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

Необходимые компоненты

  • Клиент командной строки MySQL.

  • cURL или подобная служебная HTTP-программа, с помощью которой можно протестировать функциональные возможности.

См. пример приложения

В этой статье вы закодируем пример приложения. Если вы хотите ускорить работу, готовое приложение доступно здесь: https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-mysql.

Подготовка среды выполнения

Сначала настройте некоторые переменные среды, выполнив следующие команды:

export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_MYSQL_ADMIN_USERNAME=spring
export AZ_MYSQL_ADMIN_PASSWORD=<YOUR_MYSQL_ADMIN_PASSWORD>
export AZ_MYSQL_NON_ADMIN_USERNAME=spring-non-admin
export AZ_MYSQL_NON_ADMIN_PASSWORD=<YOUR_MYSQL_NON_ADMIN_PASSWORD>

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

  • <YOUR_DATABASE_NAME>: имя сервера MySQL, который должен быть уникальным в Azure.
  • <YOUR_AZURE_REGION>: регион Azure, который вы будете использовать. Вы можете использовать eastus по умолчанию, но мы рекомендуем настроить регион, расположенный близко к месту проживания. Полный список доступных регионов можно просмотреть с помощью az account list-locations.
  • <YOUR_MYSQL_ADMIN_PASSWORD> и <YOUR_MYSQL_NON_ADMIN_PASSWORD>: пароль сервера базы данных MySQL, который должен содержать не менее восьми символов. и включать знаки всех следующих типов: прописные латинские буквы, строчные латинские буквы, цифры (0–9) и небуквенно-цифровые знаки (!, $, #, % и т. д.).

Затем создайте группу ресурсов:

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

Создание экземпляра База данных Azure для MySQL и настройка пользователя администратора

Первое, что вы создадите, — это управляемый сервер MySQL с пользователем администратора.

Примечание.

См. сведения о создании серверов MySQL в руководстве Создание базы данных Azure для сервера MySQL с помощью портала Azure.

az mysql flexible-server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --location $AZ_LOCATION \
    --admin-user $AZ_MYSQL_ADMIN_USERNAME \
    --admin-password $AZ_MYSQL_ADMIN_PASSWORD \
    --yes \
    --output tsv

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

Создайте базу данных с именем demo, выполнив следующую команду:

az mysql flexible-server db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --database-name demo \
    --server-name $AZ_DATABASE_NAME \
    --output tsv

Настройка правила брандмауэра для сервера MySQL

Экземпляры Базы данных Azure для MySQL по умолчанию защищены. В них включен брандмауэр, который блокирует все входящие подключения.

Этот шаг можно пропустить, если вы используете Bash, так как flexible-server create команда уже обнаружила локальный IP-адрес и установите ее на сервере MySQL.

Если вы подключаетесь к серверу MySQL из подсистема 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 mysql flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_NAME \
    --start-ip-address $AZ_WSL_IP_ADDRESS \
    --end-ip-address $AZ_WSL_IP_ADDRESS \
    --rule-name allowiprange \
    --output tsv

Создание пользователя, отличного от администратора MySQL, и предоставление разрешений

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

Примечание.

Дополнительные сведения о создании пользователей MySQL см. в статье "Создание пользователей" в База данных Azure для MySQL.

Сначала создайте скрипт SQL с именем create_user.sql для создания пользователя без администратора. Добавьте следующее содержимое и сохраните его локально:

cat << EOF > create_user.sql
CREATE USER '$AZ_MYSQL_NON_ADMIN_USERNAME'@'%' IDENTIFIED BY '$AZ_MYSQL_NON_ADMIN_PASSWORD';
GRANT ALL PRIVILEGES ON demo.* TO '$AZ_MYSQL_NON_ADMIN_USERNAME'@'%';
FLUSH PRIVILEGES;
EOF

Затем выполните следующую команду, чтобы запустить скрипт SQL, чтобы создать пользователя без администратора:

mysql -h $AZ_DATABASE_NAME.mysql.database.azure.com --user $AZ_MYSQL_ADMIN_USERNAME --enable-cleartext-plugin --password=$AZ_MYSQL_ADMIN_PASSWORD < create_user.sql

Теперь используйте следующую команду, чтобы удалить временный файл скрипта SQL:

rm create_user.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 -

Добавление реализации реактивного драйвера MySQL

Откройте файл pom.xml созданного проекта, чтобы добавить реактивный драйвер MySQL из репозитория GitHub r2dbc-mysql.

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

<dependency>
  <groupId>io.asyncer</groupId>
  <artifactId>r2dbc-mysql</artifactId>
  <version>0.9.1</version>
</dependency>

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

Откройте файл src/main/resources/application.properties и добавьте следующее:

logging.level.org.springframework.data.r2dbc=DEBUG

spring.r2dbc.url=r2dbc:pool:mysql://$AZ_DATABASE_NAME.mysql.database.azure.com:3306/demo?tlsVersion=TLSv1.2
spring.r2dbc.username=spring-non-admin
spring.r2dbc.password=$AZ_MYSQL_NON_ADMIN_PASSWORD

Замените $AZ_DATABASE_NAME и $AZ_MYSQL_NON_ADMIN_PASSWORD переменные значениями, настроенными в начале этой статьи.

Примечание.

Для лучшей производительности в качестве значения свойства spring.r2dbc.url указан пул подключений, как описано в репозитории r2dbc-pool.

Теперь вы можете запустить приложение с помощью предоставленной оболочки Maven:

./mvnw spring-boot:run

Ниже приведен снимок экрана приложения, выполняемого в первый раз:

Screenshot of the running application.

Создание схемы базы данных

В основном классе 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 SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);

Остановите приложение и запустите его снова. Теперь приложение будет использовать созданную ранее базу данных demo и создаст в ней таблицу todo.

./mvnw spring-boot:run

Ниже приведен снимок экрана с создаваемой таблицей базы данных:

Screenshot of the creation of the database table.

Добавление кода приложения

Затем добавьте код Java, который будет использовать R2DBC для хранения и извлечения данных из сервера MySQL.

Создайте новый класс 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:

Screenshot of the cURL test.

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

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

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

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

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

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

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

См. также

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

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