Usare Spring Data R2DBC con Database di Azure per MySQL
Questo articolo illustra la creazione di un'applicazione di esempio che usa Spring Data R2DBC per archiviare e recuperare informazioni in Database di Azure per MySQL usando l'implementazione R2DBC per MySQL dal repository GitHub r2dbc-mysql.
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
Una sottoscrizione di Azure: creare un account gratuitamente.
Java Development Kit (JDK), versione 8 o successiva.
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-mysql.
Preparare l'ambiente di lavoro
Prima di tutto, configurare alcune variabili di ambiente eseguendo i comandi seguenti:
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>
Sostituire i segnaposto con i valori seguenti, che vengono usati nell'intero articolo:
-
<YOUR_DATABASE_NAME>
: nome del server MySQL, che deve essere univoco in Azure. -
<YOUR_AZURE_REGION>
: l'area di Azure da usare. È possibile usareeastus
per impostazione predefinita, ma è consigliabile configurare un'area più vicina a dove si risiede. È possibile visualizzare l'elenco completo delle aree disponibili usandoaz account list-locations
. -
<YOUR_MYSQL_ADMIN_PASSWORD>
e<YOUR_MYSQL_NON_ADMIN_PASSWORD>
: password del server di database MySQL, che deve contenere almeno otto caratteri. La password deve contenere caratteri di tre delle categorie seguenti: lettere maiuscole, lettere minuscole, numeri (0-9) e caratteri non alfanumerici (!, $, #, % e così via).
Nota
Microsoft consiglia di usare il flusso di autenticazione più sicuro disponibile. Il flusso di autenticazione descritto in questa procedura, ad esempio per database, cache, messaggistica o servizi di intelligenza artificiale, richiede un livello di attendibilità molto elevato nell'applicazione e comporta rischi non presenti in altri flussi. Usare questo flusso solo quando le opzioni più sicure, ad esempio le identità gestite per le connessioni senza password o senza chiave, non sono valide. Per le operazioni del computer locale, preferire le identità utente per le connessioni senza password o senza chiave.
Successivamente, creare un gruppo di risorse:
az group create \
--name $AZ_RESOURCE_GROUP \
--location $AZ_LOCATION \
--output tsv
Creare un'istanza di Database di Azure per MySQL e configurare l'utente amministratore
La prima cosa che si creerà è un server MySQL gestito con un utente amministratore.
Nota
Per informazioni più dettagliate sulla creazione di server MySQL, vedere Creare un server di Database di Azure per MySQL nel portale di 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
Configurare un database MySQL
Creare un nuovo database denominato demo
con il comando seguente:
az mysql flexible-server db create \
--resource-group $AZ_RESOURCE_GROUP \
--database-name demo \
--server-name $AZ_DATABASE_NAME \
--output tsv
Configurare una regola del firewall per il server MySQL
Le istanze di Database di Azure per MySQL sono protette per impostazione predefinita. Includono un firewall che non consente alcuna connessione in ingresso.
È possibile ignorare questo passaggio se si usa Bash perché il comando ha già rilevato l'indirizzo flexible-server create
IP locale e impostarlo nel server MySQL.
Se ci si connette al server MySQL 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 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
Creare un utente non amministratore di MySQL e concedere l'autorizzazione
Questo passaggio creerà un utente non amministratore e concederà tutte le autorizzazioni per il demo
database.
Nota
Per altre informazioni dettagliate sulla creazione di utenti MySQL, vedere Creare utenti in Database di Azure per MySQL.
Creare prima di tutto uno script SQL denominato create_user.sql per la creazione di un utente non amministratore. Aggiungervi il contenuto seguente e salvarlo in locale:
Nota
Microsoft consiglia di usare il flusso di autenticazione più sicuro disponibile. Il flusso di autenticazione descritto in questa procedura, ad esempio per database, cache, messaggistica o servizi di intelligenza artificiale, richiede un livello di attendibilità molto elevato nell'applicazione e comporta rischi non presenti in altri flussi. Usare questo flusso solo quando le opzioni più sicure, ad esempio le identità gestite per le connessioni senza password o senza chiave, non sono valide. Per le operazioni del computer locale, preferire le identità utente per le connessioni senza password o senza chiave.
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
Usare quindi il comando seguente per eseguire lo script SQL per creare l'utente non amministratore:
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
A questo punto, usare il comando seguente per rimuovere il file di script SQL temporaneo:
rm create_user.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 quanto segue 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 MySQL reattivo
Aprire il file pom.xml del progetto generato per aggiungere il driver MySQL reattivo dal repository GitHub r2dbc-mysql.
Dopo la dipendenza spring-boot-starter-webflux
aggiungere il frammento di codice seguente:
<dependency>
<groupId>io.asyncer</groupId>
<artifactId>r2dbc-mysql</artifactId>
<version>0.9.1</version>
</dependency>
Configurare Spring Boot per l'uso di Database di Azure per MySQL
Aprire il file src/main/resources/application.properties e aggiungere:
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
Sostituire le $AZ_DATABASE_NAME
variabili e $AZ_MYSQL_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:
./mvnw spring-boot:run
Ecco uno screenshot dell'applicazione in esecuzione per la prima volta:
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 SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);
Arrestare l'applicazione in esecuzione e quindi riavviarla. 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:
Codice dell'applicazione
Aggiungere quindi il codice Java che userà R2DBC per archiviare e recuperare i dati dal server MySQL.
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:
Complimenti. È stata creata un'applicazione Spring Boot completamente reattiva che usa R2DBC per archiviare e recuperare i dati da Database di Azure per MySQL.
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.