Ir al contenido
learn

Datos reactivos con R2DBC y Spring Data

R2DBC es un contrato reactivo para bases de datos. A diferencia de JDBC, no mantiene un hilo bloqueado por consulta. Spring Data R2DBC mapea filas y compone el trabajo como Mono y Flux.

Envolver JDBC en Flux<Row> sigue siendo bloqueante. Un controlador R2DBC real produce señales Reactive Streams desde la conexión hasta la decodificación. El módulo usa H2 R2DBC en memoria: la misma prueba funciona en Windows, Linux y macOS sin Docker.

@Table("voicing")
public record Voicing(@Id Long id, String symbol, int fret) {
public static Voicing newVoicing(String symbol, int fret) {
return new Voicing(null, symbol, fret);
}
}

R2dbcEntityTemplate equivale a usar directamente un DbContext de EF Core:

public Mono<Voicing> save(Voicing voicing) {
return template.insert(voicing);
}
public Flux<Voicing> findBySymbol(String symbol) {
return template.select(Voicing.class)
.matching(Query.query(Criteria.where("symbol").is(symbol)))
.all();
}

Nada ocurre antes de la suscripción. La prueba encadena esquema, inserciones y selección, y verifica las señales con StepVerifier. block() solo aparece en la preparación de la prueba.

mvn -B -pl l05-r2dbc -am test

Una transacción R2DBC pertenece a una conexión y es asíncrona. La segunda prueba inicia una transacción, inserta G7, revierte y prueba que la consulta siguiente está vacía. Una aplicación suele usar R2dbcTransactionManager y TransactionalOperator; la conexión explícita hace visible el ciclo de vida.

No compartas una conexión mutable entre suscriptores, no ejecutes JDBC en el event loop y no uses un ID generado antes de que termine la inserción. La backpressure controla la entrega, no la capacidad de la base de datos.

  1. Añade findAtOrAboveFret(int fret) y ordena por traste.
Solución

Usa Query.query(Criteria.where("fret").greaterThanOrEquals(fret)).sort(Sort.by("fret")) y verifica el orden con StepVerifier.expectNextMatches.

  1. Inserta dos filas en una transacción, fuerza un error y demuestra que no queda ninguna.
Solución

Compón ambos statements en la misma conexión, añade Mono.error y aplica onErrorResume solo después de rollbackTransaction(). El invariante es la atomicidad.

  1. ¿Cuándo es más sencillo JDBC sobre hilos virtuales?
Solución

Elige JDBC si el driver, el ORM y el equipo son bloqueantes y la concurrencia es moderada. Elige R2DBC si todo el camino es reactivo y la concurrencia consumiría demasiados hilos bloqueados.