Compartir a través de


Uso de Spring Data R2DBC con Azure Database for PostgreSQL

En este artículo se muestra cómo crear una aplicación de ejemplo que utiliza Spring Data R2DBC para almacenar y recuperar información de una base de datos de Azure Database for PostgreSQL. En el ejemplo se usará la implementación de R2DBC para PostgreSQL del repositorio r2dbc-postgresql en GitHub.

R2DBC aporta API reactivas a las bases de datos relacionales tradicionales. Puede usarlo con Spring WebFlux para crear aplicaciones de Spring Boot totalmente reactivas que usan API sin bloqueo. Proporciona una mejor escalabilidad que el enfoque clásico "un subproceso por conexión".

Requisitos previos

Consulte la aplicación de ejemplo

En este artículo, se codificará una aplicación de ejemplo. Si desea ir más rápido, esta aplicación ya está codificada y disponible en https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-postgresql.

Preparación del entorno de trabajo

En primer lugar, configure algunas variables de entorno mediante la ejecución de los siguientes comandos:

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>

Reemplace los marcadores de posición por los valores siguientes, que se usan a lo largo de este artículo:

  • <YOUR_DATABASE_SERVER_NAME>: el nombre del servidor de PostgreSQL, que debe ser único en Azure.
  • <YOUR_DATABASE_NAME>: el nombre de la base de datos del servidor de PostgreSQL, que debe ser único en Azure.
  • <YOUR_AZURE_REGION>: región de Azure que va a usar. Puede usar eastus de forma predeterminada, pero se recomienda que configure una región más cercana a la ubicación en la que vive. Puede ver la lista completa de regiones disponibles mediante az account list-locations.
  • <YOUR_POSTGRESQL_ADMIN_PASSWORD> y <YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>: la contraseña del servidor de base de datos postgreSQL, que debe tener un mínimo de ocho caracteres. Debe contener caracteres de tres de las siguientes categorías: Letras del alfabeto inglés mayúsculas y minúsculas, números (0-9) y caracteres no alfanuméricos (!, $, #, %, etc.).
  • <YOUR_LOCAL_IP_ADDRESS>: dirección IP del equipo local, desde el que se ejecutará la aplicación de Spring Boot. Una manera cómoda de encontrarla es abrir whatismyip.akamai.com.

Nota:

Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento, como para bases de datos, memorias caché, mensajería o servicios de inteligencia artificial, requiere un grado de confianza muy alto en la aplicación y conlleva riesgos que no están presentes en otros flujos. Use este flujo solo cuando las opciones más seguras, como las identidades administradas para conexiones sin contraseña o sin claves, no sean viables. En el caso de las operaciones de máquina local, prefiera identidades de usuario para conexiones sin contraseña o sin claves.

A continuación, cree un grupo de recursos con el siguiente comando:

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

Creación de una instancia de Azure Database for PostgreSQL y configuración del usuario administrador

Lo primero que va a crear es un servidor de PostgreSQL administrado con un usuario administrador.

Nota

Puede leer información más detallada sobre la creación de servidores de PostgreSQL en Creación de un servidor de Azure Database for PostgreSQL mediante Azure Portal.

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

Configuración de una base de datos PostgreSQL

El servidor de PostgreSQL que creó anteriormente está vacío. Use el siguiente comando para crear una nueva base de datos.

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

Configuración de una regla de firewall para el servidor de PostgreSQL

De forma predeterminada, las instancias de Azure Database for PostgreSQL están protegidas. Tienen un firewall que no permite ninguna conexión entrante. Para poder usar la base de datos, es necesario agregar una regla de firewall que permita a la dirección IP local acceder al servidor de base de datos.

Como hemos configurado nuestra dirección IP local al principio de este artículo, puede abrir el firewall del servidor con el siguiente 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

Si se conecta al servidor de PostgreSQL desde el subsistema de Windows para Linux (WSL) en un equipo Windows, debe agregar el identificador de host de WSL al firewall.

Para obtener la dirección IP de la máquina host, ejecute el siguiente comando en WSL:

cat /etc/resolv.conf

Copie la dirección IP que sigue al término nameserver y, a continuación, use el siguiente comando para establecer una variable de entorno para la dirección IP de WSL:

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

A continuación, use el siguiente comando para abrir el firewall del servidor en la aplicación basada en 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

Cree un usuario que no es administrador de PostgreSQL y conceda permisos

A continuación, cree un usuario que no sea administrador y concédale todos los permisos para la base de datos.

Nota

Puede leer información más detallada sobre cómo crear usuarios de PostgreSQL en Creación de usuarios en Azure Database for PostgreSQL.

Cree un script SQL denominado create_user.sql para crear un usuario que no sea administrador. Agregue el siguiente contenido y guárdelo de forma local:

Nota:

Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento, como para bases de datos, memorias caché, mensajería o servicios de inteligencia artificial, requiere un grado de confianza muy alto en la aplicación y conlleva riesgos que no están presentes en otros flujos. Use este flujo solo cuando las opciones más seguras, como las identidades administradas para conexiones sin contraseña o sin claves, no sean viables. En el caso de las operaciones de máquina local, prefiera identidades de usuario para conexiones sin contraseña o sin claves.

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

A continuación, use el siguiente comando para ejecutar el script SQL para crear el usuario que no es administrador de 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

Ahora use el siguiente comando para quitar el archivo de script SQL temporal:

rm create_user.sql

Creación de una aplicación reactiva de Spring Boot

Para crear una aplicación reactiva de Spring Boot, usaremos Spring Initializr. La aplicación que vamos a crear utiliza:

  • Spring Boot 2.7.11.
  • Las dependencias siguientes: Spring Reactive Web (también conocido como Spring WebFlux) y Spring Data R2DBC.

Generación de la aplicación con Spring Initializr

Genere la aplicación en la línea de comandos con el siguiente 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 -

Adición de la implementación del controlador reactivo de PostgreSQL

Abra el archivo pom.xml del proyecto generado y agregue el controlador reactivo de PostgreSQL desde el repositorio r2dbc-postgresql de GitHub. Después de la dependencia spring-boot-starter-webflux, agregue el siguiente texto:

<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-postgresql</artifactId>
    <version>0.8.12.RELEASE</version>
    <scope>runtime</scope>
</dependency>

Configuración de Spring Boot para el uso de Azure Database for PostgreSQL

Abra el archivo src/main/resources/application.properties y agregue el texto siguiente:

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

Reemplace las $AZ_DATABASE_SERVER_NAMEvariables , $AZ_DATABASE_NAMEy $AZ_POSTGRESQL_NON_ADMIN_PASSWORD por los valores que configuró al principio de este artículo.

Advertencia

Por motivos de seguridad, Azure Database for PostgreSQL requiere el uso de conexiones SSL. Esta es la razón por la que necesita agregar la propiedad de configuración spring.r2dbc.properties.sslMode=REQUIRE; de lo contrario, el controlador R2DBC de PostgreSQL intentará conectarse con una conexión no segura y se producirá un error.

Nota:

Para mejorar el rendimiento, la propiedad spring.r2dbc.url está configurada para usar un grupo de conexiones con r2dbc-pool.

Ahora podrá iniciar la aplicación mediante el contenedor de Maven proporcionado, de la siguiente manera:

./mvnw spring-boot:run

Esta es una captura de pantalla de la primera ejecución de la aplicación:

Captura de pantalla de la aplicación en ejecución.

Creación del esquema de la base de datos

Dentro de la clase DemoApplication principal, configure un nuevo bean de Spring que creará el esquema de la base de datos, con el siguiente código:

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

Este bean de Spring usa un archivo llamado schema.sql, por lo que debe crear dicho archivo en la carpeta src/main/resources y agregar el siguiente texto:

DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);

Detenga la aplicación e iníciela de nuevo con el siguiente comando. La aplicación usará ahora la base de datos demo que creó anteriormente y creará la tabla todo dentro de ella.

./mvnw spring-boot:run

Esta es una captura de pantalla de la tabla de base de datos que se está creando:

Captura de pantalla de la creación de la tabla de base de datos.

Incorporación del código de la aplicación

A continuación, agregue el código Java que usará R2DBC para almacenar y recuperar datos del servidor de PostgreSQL.

Cree la nueva clase Todo de Java junto a la clase DemoApplication, con el siguiente código:

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

Esta clase es un modelo de dominio asignado a la tabla todo que creó antes.

Para administrar esa clase, necesitará un repositorio. Defina una nueva interfaz TodoRepository en el mismo paquete, con el siguiente código:

package com.example.demo;

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

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

Este es un repositorio reactivo que Spring Data R2DBC administra.

Finalice la aplicación mediante la creación de un controlador que pueda almacenar y recuperar datos. Implemente la clase TodoController en el mismo paquete y agregue el código siguiente:

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

Por último, detenga la aplicación e iníciela de nuevo con el siguiente comando:

./mvnw spring-boot:run

Prueba de la aplicación

Puede usar cURL para probar la aplicación.

En primer lugar, cree un nuevo elemento "todo" en la base de datos con el siguiente comando:

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

Este comando devolverá el elemento creado, como se muestra aquí:

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

A continuación, recupere los datos mediante una nueva solicitud cURL, con el siguiente comando:

curl http://127.0.0.1:8080

Este comando devolverá la lista de elementos "todo", incluido el elemento que ha creado, como se muestra aquí:

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

Esta es una captura de pantalla de estas solicitudes cURL:

Captura de pantalla de la prueba de cURL.

Felicidades. Ha creado una aplicación de Spring Boot totalmente reactiva que usa R2DBC para almacenar y recuperar datos de Azure Database for PostgreSQL.

Limpieza de recursos

Para limpiar todos los recursos usados durante este inicio rápido, elimine el grupo de recursos mediante el siguiente comando:

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

Pasos siguientes

Para más información sobre la implementación de una aplicación Spring Data en Azure Spring Apps y el uso de la identidad administrada, consulte Tutorial: Implementación de una aplicación spring en Azure Spring Apps con una conexión sin contraseña a una base de datos de Azure.

Para más información acerca de Spring y Azure, vaya al centro de documentación de Azure.

Consulte también

Para más información sobre Spring Data R2DBC, consulte la documentación de referencia de Spring.

Para más información sobre el uso de Azure con Java, consulte Azure para desarrolladores de Java y Trabajo con Azure DevOps y Java.