Usare Spring Data R2DBC con il database SQL di Azure

Questo articolo illustra la creazione di un'applicazione di esempio che usa Spring Data R2DBC per archiviare e recuperare informazioni in database SQL di Azure usando l'implementazione R2DBC per Microsoft SQL Server dal repository GitHub r2dbc-mssql.

R2DBC introduce le API reattive nei database relazionali tradizionali. È possibile usarlo con Spring WebFlux per creare applicazioni Spring Boot completamente reattive che usano API non bloccanti. Offre una migliore scalabilità rispetto all'approccio classico di "un thread per connessione".

Prerequisiti

  • Utilità sqlcmd.

  • cURL o un'utilità HTTP simile per testare la funzionalità.

Vedere l'applicazione di esempio

In questo articolo verrà codificata un'applicazione di esempio. Per procedere più rapidamente, è possibile usare l'applicazione già pronta, disponibile all'indirizzo https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-sql-server.

Preparare l'ambiente di lavoro

Prima di tutto, configurare alcune variabili di ambiente usando i comandi seguenti:

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>

Sostituire i segnaposto con i valori seguenti, che vengono usati nell'intero articolo:

  • <YOUR_DATABASE_NAME>: nome del server database SQL di Azure, che deve essere univoco in Azure.
  • <YOUR_AZURE_REGION>: l'area di Azure che verrà usata. È possibile usare eastus per impostazione predefinita, ma è consigliabile configurare un'area più vicina a dove si risiede. È possibile visualizzare l'elenco completo delle aree disponibili usando az account list-locations.
  • <AZ_SQL_SERVER_ADMIN_PASSWORD>e <AZ_SQL_SERVER_NON_ADMIN_PASSWORD>: password del server database SQL di Azure, che deve contenere almeno otto caratteri. I caratteri devono essere compresi tra tre delle categorie seguenti: lettere maiuscole, lettere minuscole, numeri (0-9) e caratteri non alfanumerici (!, $, #, %e così via).
  • <YOUR_LOCAL_IP_ADDRESS>: indirizzo IP del computer locale, da cui si eseguirà l'applicazione Spring Boot. Un modo pratico per trovare è aprire whatismyip.akamai.com.

Creare quindi un gruppo di risorse usando il comando seguente:

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

Creare un'istanza del database SQL di Azure

Creare quindi un'istanza del server gestita database SQL di Azure eseguendo il comando seguente.

Nota

La password MS SQL deve soddisfare criteri specifici e la configurazione avrà esito negativo con una password non conforme. Per ulteriori informazioni, vedere 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

Configurare una regola del firewall per il server di database SQL di Azure

Le istanze del database SQL di Azure sono protette per impostazione predefinita. Includono un firewall che non consente alcuna connessione in ingresso. Per poter usare il database, è necessario aggiungere una regola del firewall che consenta all'indirizzo IP locale di accedere al server di database.

Poiché all'inizio di questo articolo è stato configurato un indirizzo IP locale, è possibile aprire il firewall del server eseguendo questo comando:

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

Se ci si connette al server database SQL di Azure da sottosistema Windows per Linux (WSL) in un computer Windows, è necessario aggiungere l'ID host WSL al firewall.

Ottenere l'indirizzo IP del computer host eseguendo il comando seguente in WSL:

cat /etc/resolv.conf

Copiare l'indirizzo IP seguendo il termine nameserver, quindi usare il comando seguente per impostare una variabile di ambiente per l'indirizzo IP WSL:

export AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Usare quindi il comando seguente per aprire il firewall del server all'app basata su 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

Configurare un database SQL di Azure

Il database SQL di Azure creato in precedenza è vuoto. Non include nessun database che è possibile usare con l'applicazione Spring Boot. Creare un nuovo database denominato demo eseguendo questo comando:

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

Creare un utente non amministratore del database SQL e concedere l'autorizzazione

Questo passaggio creerà un utente non amministratore e concederà tutte le autorizzazioni per il demo database.

Creare uno script SQL denominato create_user.sql per la creazione di un utente non amministratore. Aggiungere il contenuto seguente e salvarlo in locale:

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

Usare quindi il comando seguente per eseguire lo script SQL per creare l'utente non amministratore:

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

Nota

Per altre informazioni sulla creazione di utenti di database SQL, vedere CREATE U edizione Standard R (Transact-SQL).


Creare un'applicazione Spring Boot reattiva

Per creare un'applicazione Spring Boot reattiva, si userà Spring Initializr. L'applicazione che verrà creata usa:

  • Spring Boot 2.7.11.
  • Le dipendenze seguenti: Spring Reactive Web (nota anche come Spring WebFlux) e Spring Data R2DBC.

Generare l'applicazione con Spring Initializr

Per generare l'applicazione, immettere il comando seguente sulla riga di comando:

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 -

Aggiungere l'implementazione del driver del database SQL di Azure reattivo

Aprire il file pom.xml del progetto generato per aggiungere il driver del database SQL di Azure reattivo dal repository GitHub r2dbc-mssql.

Dopo la dipendenza spring-boot-starter-webflux aggiungere il testo seguente:

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

Configurare Spring Boot per l'uso del database SQL di Azure

Aprire il file src/main/resources/application.properties e aggiungere il testo seguente:

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

Sostituire le due variabili $AZ_DATABASE_NAME e la variabile $AZ_SQL_SERVER_NON_ADMIN_PASSWORD con i valori configurati all'inizio di questo articolo.

Nota

Per prestazioni più elevate, la proprietà spring.r2dbc.url viene configurata per l'uso di un pool di connessioni tramite r2dbc-pool.

A questo punto dovrebbe essere possibile avviare l'applicazione usando il wrapper Maven fornito, come segue:

./mvnw spring-boot:run

Ecco uno screenshot dell'applicazione in esecuzione per la prima volta:

Screenshot of the running application.

Creare lo schema del database

All'interno della classe DemoApplication principale configurare un nuovo bean Spring che creerà uno schema del database, usando il codice seguente:

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

Questo bean Spring usa un file denominato schema.sql, quindi creare il file nella cartella src/main/resources e aggiungere il testo seguente:

DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id INT IDENTITY PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BIT);

Arrestare l'applicazione in esecuzione e quindi riavviarla usando il comando seguente. L'applicazione userà ora il database demo creato in precedenza e creerà una todo tabella al suo interno.

./mvnw spring-boot:run

Ecco uno screenshot della tabella di database creata:

Screenshot of the creation of the database table.

Codice dell'applicazione

Aggiungere quindi il codice Java che userà R2DBC per archiviare e recuperare i dati dal server di database SQL di Azure.

Creare una nuova classe Java Todo accanto alla classe DemoApplication usando il codice seguente:

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

Questa classe è un modello di dominio mappato alla tabella todo creata in precedenza.

Per gestire questa classe è necessario un repository. Definire una nuova interfaccia TodoRepository nello stesso pacchetto usando il codice seguente:

package com.example.demo;

import org.springframework.data.repository.reactive.ReactiveCrudRepository;

public interface TodoRepository extends ReactiveCrudRepository<Todo, Long> {
}

Questo repository è un repository reattivo gestito da Spring Data R2DBC.

Completare l'applicazione creando un controller in grado di archiviare e recuperare dati. Implementare una classe TodoController nello stesso pacchetto e aggiungere il codice seguente:

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

Infine, arrestare l'applicazione e quindi riavviarla usando il comando seguente:

./mvnw spring-boot:run

Testare l'applicazione

Per testare l'applicazione, è possibile usare cURL.

Creare prima di tutto un elemento "todo" nel database con il comando seguente:

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

Questo comando restituirà l'elemento creato, come illustrato qui:

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

Recuperare quindi i dati usando una nuova richiesta cURL con il comando seguente:

curl http://127.0.0.1:8080

Questo comando restituirà l'elenco di elementi "todo", incluso quello creato, come illustrato qui:

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

Ecco uno screenshot di queste richieste cURL:

Screenshot of the cURL test.

Complimenti. È stata creata un'applicazione Spring Boot completamente reattiva che usa R2DBC per archiviare e recuperare i dati dal database SQL di Azure.

Pulire le risorse

Per pulire tutte le risorse usate durante questa guida introduttiva, eliminare il gruppo di risorse usando il comando seguente:

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

Passaggi successivi

Per altre informazioni sulla distribuzione di un'applicazione Spring Data in Azure Spring Apps e sull'uso dell'identità gestita, vedere Esercitazione: Distribuire un'applicazione Spring in Azure Spring Apps con una connessione senza password a un database di Azure.

Per altre informazioni su Spring e Azure, passare al centro di documentazione di Spring in Azure.

Vedi anche

Per altre informazioni su Spring Data R2DBC, vedere la documentazione di riferimento di Spring.

Per altre informazioni sull'uso di Azure con Java, vedere Azure per sviluppatori Java e la documentazione relativa all'uso di Azure DevOps e Java.