Uma rápida olhada no R2DBC com dados da Spring

Uma rápida olhada no R2DBC com dados da Spring

1. Introdução

R2DBC (conectividade reativa de banco de dados relacional) é um esforço apresentado pela Pivotal durante o Spring One Platform 2018. Ele pretende criar uma API reativa para bancos de dados SQL.

Em outras palavras, esse esforço cria uma conexão de banco de dados usando drivers totalmente não bloqueadores.

Neste tutorial, daremos uma olhada em um exemplo de um aplicativo usando Spring Data R2BDC. Para obter um guia para a API R2DBC de nível mais baixo, dê uma olhada emour previous article.

2. Nosso primeiro projeto R2DBC de dados de primavera

Para começar, o projeto R2DBC é muito recente. Neste momento, apenasPostGres, MSSQL, and H2 have R2DBC drivers. Além disso,we can’t use all Spring Boot functionality com ele. Portanto, há algumas etapas que precisamos adicionar manualmente. Mas,we can leverage projects like Spring Data to help us.

Vamos criar um projeto Maven primeiro. Neste ponto, existem alguns problemas de dependência com R2DBC, então nossopom.xml será maior do que normalmente.

Para o escopo deste artigo, usaremosH2 como nosso banco de dados e criaremos funções CRUD reativas para nosso aplicativo.

Vamos abrirpom.xml do projeto gerado e adicionar as dependências apropriadas, bem como alguns repositórios Spring de lançamento antecipado:


     
        org.springframework.data
        spring-data-r2dbc
        1.0.0.M2
    
    
        io.r2dbc
        r2dbc-h2
        0.8.0.M8
    
    
        com.h2database
        h2
        1.4.199
    



    
        spring-snapshots
        Spring Snapshots
        https://repo.spring.io/snapshot
        
            true
        
    
    
        spring-milestones
        Spring Milestones
        https://repo.spring.io/milestone
    

Precisamos desses repositórios para usar as dependências dos marcos.

Outros artefatos necessários incluemLombok,Spring WebFluxe alguns outros que completam nosso projetodependencies.

3. Fábrica de conexão

Ao trabalhar com um banco de dados, precisamos de um connection factory. Então, é claro, vamos precisar da mesma coisa com R2DBC.

Portanto, agora adicionaremos os detalhes para conectar à nossa instância:

@Configuration
@EnableR2dbcRepositories
class R2DBCConfiguration extends AbstractR2dbcConfiguration {
    @Bean
    public H2ConnectionFactory connectionFactory() {
        return new H2ConnectionFactory(
            H2ConnectionConfiguration.builder()
              .url("mem:testdb;DB_CLOSE_DELAY=-1;")
              .username("sa")
              .build()
        );
    }
}

A primeira coisa que observamos no código acima é@EnableR2dbcRepositories. Precisamos desta anotação para usar a funcionalidade Spring Data. Além disso, somosextending the AbstractR2dbcConfiguration since it’ll provide a lot of beans that we’d need later on.

4. Nossa primeira aplicação R2DBC

Nosso próximo passo é criar o repositório:

interface PlayerRepository extends ReactiveCrudRepository {}

A interfaceReactiveCrudRepository é muito útil. Ele fornece, por exemplo, funcionalidade CRUD básica.

Finalmente, definiremos nossa classe de modelo. Usaremos o Lombok para evitar o código clichê:

@Data
@NoArgsConstructor
@AllArgsConstructor
class Player {
    @Id
    Integer id;
    String name;
    Integer age;
}

5. Teste

É hora detest nosso código. Então, vamos começar criando alguns casos de teste:

@Test
public void whenDeleteAll_then0IsExpected() {
    playerRepository.deleteAll()
      .as(StepVerifier::create)
      .expectNextCount(0)
      .verifyComplete();
}

@Test
public void whenInsert6_then6AreExpected() {
    insertPlayers();
    playerRepository.findAll()
      .as(StepVerifier::create)
      .expectNextCount(6)
      .verifyComplete();
}

6. Consultas personalizadas

We can also generate custom queries. Para adicioná-lo, precisaremos alterar nossoPlayerRepository:

@Query("select id, name, age from player where name = $1")
Flux findAllByName(String name);

@Query("select * from player where age = $1")
Flux findByAge(int age);

Além dos testes existentes, adicionaremos testes ao nosso repositório atualizado recentemente:

@Test
public void whenSearchForCR7_then1IsExpected() {
    insertPlayers();
    playerRepository.findAllByName("CR7")
      .as(StepVerifier::create)
      .expectNextCount(1)
      .verifyComplete();
}

@Test
public void whenSearchFor32YearsOld_then2AreExpected() {
    insertPlayers();
    playerRepository.findByAge(32)
      .as(StepVerifier::create)
      .expectNextCount(2)
      .verifyComplete();
}

private void insertPlayers() {
    List players = Arrays.asList(
        new Player(1, "Kaka", 37),
        new Player(2, "Messi", 32),
        new Player(3, "Mbappé", 20),
        new Player(4, "CR7", 34),
        new Player(5, "Lewandowski", 30),
        new Player(6, "Cavani", 32)
    );
    playerRepository.saveAll(players).subscribe();
}

7. Lotes

Outro recurso do R2DBC é criar lotes. Um lote é útil ao executar várias instruções SQL, pois elas terão um desempenho melhor do que as operações individuais.

Para criar umBatch, precisamos de um objetoConnection:

Batch batch = connection.createBatch();

Depois que nosso aplicativo cria a instânciaBatch, podemos adicionar quantas instruções SQL quisermos. Para executá-lo, invocaremos o métodoexecute() . O resultado de um lote é umPublisher que retornará um objeto de resultado para cada instrução.

Então, vamos pular para o código e ver como podemos criar umBatch:

@Test
public void whenBatchHas2Operations_then2AreExpected() {
    Mono.from(factory.create())
      .flatMapMany(connection -> Flux.from(connection
        .createBatch()
        .add("select * from player")
        .add("select * from player")
        .execute()))
      .as(StepVerifier::create)
      .expectNextCount(2)
      .verifyComplete();
}

8. Conclusão

Para resumir, o R2DBC ainda está em um estágio inicial. É uma tentativa de criar um SPI que definirá uma API reativa para bancos de dados SQL. Quando usado comSpring WebFlux, R2DBC nos permite escrever um aplicativo que trata os dados de forma assíncrona desde o início até o banco de dados.

Como sempre, o código está disponível emGitHub.