Usare Spring Data R2DBC con Database di Azure per PostgreSQL
Questo articolo illustra la creazione di un'applicazione di esempio che usa Spring Data R2DBC per archiviare e recuperare informazioni in un database Database di Azure per PostgreSQL. L'esempio usa l'implementazione di R2DBC per PostgreSQL dal repository r2dbc-postgresql in GitHub.
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-postgresql.
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_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_POSTGRESQL_ADMIN_USERNAME=spring
export AZ_POSTGRESQL_ADMIN_PASSWORD=<YOUR_POSTGRESQL_ADMIN_PASSWORD>
export AZ_POSTGRESQL_NON_ADMIN_USERNAME=nonspring
export AZ_POSTGRESQL_NON_ADMIN_PASSWORD=<YOUR_POSTGRESQL_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_SERVER_NAME>
: nome del server PostgreSQL, che deve essere univoco in Azure.<YOUR_DATABASE_NAME>
: nome del database del server PostgreSQL, che deve essere univoco all'interno di 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_POSTGRESQL_ADMIN_PASSWORD>
e<YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>
: password del server di database PostgreSQL, 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).<YOUR_LOCAL_IP_ADDRESS>
: indirizzo IP del computer locale, da cui verrà eseguita l'applicazione Spring Boot. Un modo pratico per trovarlo è aprire whatismyip.akamai.com.
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.
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 di Database di Azure per PostgreSQL e configurare l'utente amministratore
La prima cosa che si creerà è un server PostgreSQL gestito con un utente amministratore.
Nota
Per informazioni più dettagliate sulla creazione di server PostgreSQL, vedere Creare un server di Database di Azure per PostgreSQL nel portale di Azure.
az postgres flexible-server create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--location $AZ_LOCATION \
--admin-user $AZ_POSTGRESQL_ADMIN_USERNAME \
--admin-password $AZ_POSTGRESQL_ADMIN_PASSWORD \
--yes \
--output tsv
Configurare un database PostgreSQL
Il server PostgreSQL creato in precedenza è vuoto. Usare il comando seguente per creare un nuovo database.
az postgres flexible-server db create \
--resource-group $AZ_RESOURCE_GROUP \
--database-name $AZ_DATABASE_NAME \
--server-name $AZ_DATABASE_SERVER_NAME \
--output tsv
Configurare una regola del firewall per il server PostgreSQL
Le istanze di Database di Azure per PostgreSQL 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 postgres flexible-server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
--start-ip-address $AZ_LOCAL_IP_ADDRESS \
--end-ip-address $AZ_LOCAL_IP_ADDRESS \
--output tsv
Se ci si connette al server PostgreSQL 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 postgres flexible-server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_SERVER_NAME \
--rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
--start-ip-address $AZ_WSL_IP_ADDRESS \
--end-ip-address $AZ_WSL_IP_ADDRESS \
--output tsv
Creare un utente non amministratore di PostgreSQL e concedere l'autorizzazione
Creare quindi un utente non amministratore e concedere tutte le autorizzazioni al database.
Nota
Per altre informazioni dettagliate sulla creazione di utenti PostgreSQL, vedere Creare utenti in Database di Azure per PostgreSQL.
Creare 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 ROLE "$AZ_POSTGRESQL_NON_ADMIN_USERNAME" WITH LOGIN PASSWORD '$AZ_POSTGRESQL_NON_ADMIN_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE $AZ_DATABASE_NAME TO "$AZ_POSTGRESQL_NON_ADMIN_USERNAME";
EOF
Quindi, usare il comando seguente per eseguire lo script SQL per creare l'utente non amministratore di Microsoft Entra:
psql "host=$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com user=$AZ_POSTGRESQL_ADMIN_USERNAME dbname=$AZ_DATABASE_NAME port=5432 password=$AZ_POSTGRESQL_ADMIN_PASSWORD sslmode=require" < 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 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 PostgreSQL reattivo
Aprire il file pom.xml del progetto generato, quindi aggiungere il driver PostgreSQL reattivo dal repository r2dbc-postgresql in GitHub. Dopo la dipendenza spring-boot-starter-webflux
aggiungere il testo seguente:
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<version>0.8.12.RELEASE</version>
<scope>runtime</scope>
</dependency>
Configurare Spring Boot per l'uso di Database di Azure per PostgreSQL
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:postgres://$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com:5432/$AZ_DATABASE_NAME
spring.r2dbc.username=nonspring
spring.r2dbc.password=$AZ_POSTGRESQL_NON_ADMIN_PASSWORD
spring.r2dbc.properties.sslMode=REQUIRE
Sostituire le $AZ_DATABASE_SERVER_NAME
variabili , $AZ_DATABASE_NAME
e $AZ_POSTGRESQL_NON_ADMIN_PASSWORD
con i valori configurati all'inizio di questo articolo.
Avviso
Per motivi di sicurezza, con Database di Azure per PostgreSQL è necessario usare connessioni SSL. Questo è il motivo per cui è necessario aggiungere la proprietà di configurazione spring.r2dbc.properties.sslMode=REQUIRE
. In caso contrario, il driver PostgreSQL R2DBC proverà, senza riuscirci, a connettersi usando una connessione non sicura.
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:
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 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:
Codice dell'applicazione
Aggiungere quindi il codice Java che userà R2DBC per archiviare e recuperare i dati dal server PostgreSQL.
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 PostgreSQL.
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.