Exercício – Criar, ler, atualizar e excluir dados NoSQL de forma programática

Concluído

Você fez a conexão com o Azure Cosmos DB. Nesta unidade, você criará documentos do usuário em sua coleção WebCustomers. Em seguida, recuperará os documentos pela ID e fará a substituição e exclusão deles.

Trabalhando com documentos de forma programática

Os dados são armazenados em documentos JSON no Azure Cosmos DB. Os documentos podem ser criados, recuperados, substituídos ou excluídos no portal ou programaticamente. Este laboratório se concentra em operações programáticas. O Azure Cosmos DB fornece SDKs de cliente para .NET, .NET Core, Java, Node.js e Python, cada um dos quais dá suporte a essas operações. Neste módulo, usaremos o SDK do Java para executar operações CRUD (criar, recuperar, atualizar e excluir) nos dados NoSQL armazenados no Azure Cosmos DB.

As principais operações para documentos do Azure Cosmos DB fazem parte da classe CosmosAsyncContainer:

O Upsert executa uma operação de criação ou substituição, dependendo de o documento já existir ou não.

Para executar qualquer uma dessas operações, você precisará de classes auxiliares (classes POJO do Java) que representam os objetos armazenados no banco de dados. Como estamos trabalhando com um banco de dados de usuários, convém ter uma classe User representando as entidades de usuário. Essa classe armazenará dados primários, como nome, sobrenome e ID de usuário. (A ID é necessária porque ela é a chave de partição para habilitar a escala horizontal.)

Cada usuário tem algumas preferências de envio e cupons associados a ele, portanto, convém que os tipos de dados ShippingPreference e CouponsUsed representem essas entidades também. Por fim, cada usuário pode ter algum histórico de pedidos potencialmente desassociado, portanto, é recomendável ter entidades OrderHistory separadas com uma classe POJO do Java correspondente.

Vá para src/main/java/com/Azure/Azure-Cosmos-Java-SQL-app-mslearn e examine a pasta datatypes. Você verá vários POJOs: User, ShippingPreference, OrderHistory e CouponsUsed. Portanto, fornecemos todos os POJOs de entidade e as classes auxiliares deles.

Em seguida, criaremos algumas entidades e realizaremos algumas operações CRUD básicas no contêiner do Azure Cosmos DB e nos documentos que ele contém. Você pode passar para o Azure Cosmos DB um ObjectNode do Jackson que especifica diretamente o documento JSON. Entretanto, o Azure Cosmos DB também é capaz de serializar POJOs do Java em JSON, e recomendamos essa abordagem como a opção mais simples (caso o restante seja igual).

Criar documentos

  1. Abra User.java e examine o conteúdo. Ele deverá ser semelhante a este:

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
    
        /** Document ID (required by Azure Cosmos DB). */
        private String id;
    
        /** User ID. */
        private String userId;
    
        /** User last name. */
        private String lastName;
    
        /** User first name. */
        private String firstName;
    
        /** User email address. */
        private String email;
    
        /** User dividend setting. */
        private String dividend;
    
        /** User shipping preferences. */
        private ShippingPreference shippingPreference;
    
        /** User order history. */
        private List<OrderHistory> orderHistory;
    
        /** Coupons recorded by the user. */
        private List<CouponsUsed> coupons;
    }
    

    Observe que os métodos de acesso aos campos iduserId e outros são implícitos (não definidos no código). Esse comportamento é possível porque usamos a anotação @Data do Project Lombok para criá-los automaticamente.

    A anotação @NoArgsConstructor gerará um construtor sem argumentos que define valores de campo padrão. A anotação @AllArgsConstructor gerará outro construtor com um conjunto completo de argumentos para especificar todos os valores de campo diretamente.

    Observe que User tem uma propriedade id. Todos os documentos do Azure Cosmos DB exigem uma propriedade id, portanto, todos os POJOs que pretendemos serializar em documentos JSON precisam ter um campo id.

  2. Adicione o seguinte método a CosmosApp.java:

    /**
     * Take in list of Java POJOs, check if each exists, and if not insert it.
     * @param users List of User POJOs to insert.
     */
    private static void createUserDocumentsIfNotExist(final List<User> users) {
        Flux.fromIterable(users).flatMap(user -> {
            try {
                container.readItem(user.getId(), new PartitionKey(user.getUserId()), User.class).block();
                logger.info("User {} already exists in the database", user.getId());
                return Mono.empty();
            } catch (Exception err) {
                logger.info("Creating User {}", user.getId());
                return container.createItem(user, new PartitionKey(user.getUserId()), new CosmosItemRequestOptions());
            }
        }).blockLast();
    }
    
  3. Retorne para o método basicOperations e adicione o seguinte ao final dele, antes da chamada client.close().

    User maxaxam = new User(
        "1",
        "maxaxam",
        "Axam",
        "Max",
        "maxaxam@contoso.com",
        "2.0",
        new ShippingPreference(
            1,
            "90 W 8th St",
            "",
            "New York",
            "NY",
            "10001",
            "USA"
        ),
        new ArrayList<OrderHistory>(Arrays.asList(
            new OrderHistory(
                "3",
                "1000",
                "08/17/2018",
                "52.49"
            )
        )),
        new ArrayList<CouponsUsed>(Arrays.asList(
            new CouponsUsed(
                "A7B89F"
            )
        ))
    );
    
    User nelapin = new User(
            "2",
            "nelapin",
            "Pindakova",
            "Nela",
            "nelapin@contoso.com",
            "8.50",
            new ShippingPreference(
                1,
                "505 NW 5th St",
                "",
                "New York",
                "NY",
                "10001",
                "USA"
            ),
            new ArrayList<OrderHistory>(Arrays.asList(
                new OrderHistory(
                    "4",
                    "1001",
                    "08/17/2018",
                    "105.89"
                )
            )),
            new ArrayList<CouponsUsed>(Arrays.asList(
                new CouponsUsed(
                    "Fall 2018"
                )
            ))
    );
    
    createUserDocumentsIfNotExist(new ArrayList<User>(Arrays.asList(maxaxam, nelapin)));
    
  4. Crie e execute o CosmosApp.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
    

    O terminal exibirá a saída conforme o aplicativo cria cada novo documento de usuário.

    INFO: Database and container validation complete
    INFO: Creating User 1
    INFO: Creating User 2
    

    Você também poderá ver um texto adicional emitido pelo agente, como carimbos de data/hora.

Parabéns! Você criou seus primeiros dados no Azure Cosmos DB a partir de um aplicativo Java. Vamos pausar e avaliar o que você fez aqui.

Em basicOperations, há três novas ações:

  1. Criar a instância User maxaxam.
  2. Criar a instância User nelapin.
  3. Chamar createUserDocumentsIfNotExist, passando maxaxam e nelapin em uma lista.

Chamar createUserDocumentsIfNotExist insere as duas instâncias de User como itens/documentos no Azure Cosmos DB. Quando você passa as instâncias de User como uma lista, nossa intenção é modelar um método de alto desempenho para ingerir POJOs rapidamente no Azure Cosmos DB, usando recursos de computação mínimos. O createUserDocumentsIfNotExist implementa a inserção assíncrona eficiente de uma lista de POJOs.

Suponha que a nossa meta seja maximizar solicitações/segundo por thread. Para fins de comparação, a abordagem de sincronização para gravar createUserDocumentsIfNotExist (ignorando por um momento a verificação readItem) seria iterar em cada instância User em users. Para cada User u, faríamos uma chamada de bloqueio para createItem:

container.createItem(u, new PartitionKey(u.getUserId()), new CosmosItemRequestOptions()).block(); // <= Note the .block() which loops until request response.

Esse estilo de sincronização implementa um processo intuitivo: emitir a solicitação, aguardar a resposta, emitir a próxima solicitação. No entanto, o createUserDocumentsIfNotExist não usa essa abordagem porque as chamadas de bloqueio causarão essencialmente um desperdício dos ciclos de CPU durante o tempo de resposta da solicitação, fazendo com que haja um volume baixo de solicitações/segundo.

Você pode contornar esse problema de solicitações/segundo gerando vários threads para fazer chamadas de solicitação de bloqueio em paralelo. Vários threads resultarão em um aprimoramento do tempo de execução. No entanto, se a sua meta for economizar recursos de thread, isso ainda será um desperdício. Cada thread executa loops durante o tempo de resposta da solicitação, quando poderia estar realizando multitarefa para outro item, o que resulta em um volume baixo de solicitações/segundo por thread.

Por esse motivo e para mostrar a você a inserção eficiente de threads de POJOs do Java, fornecemos, em vez disso, um exemplo assíncrono de inserção de documento. O suporte assíncrono do SDK do Java do Azure Cosmos DB v4 é proveniente do Project Reactor, uma estrutura do aplicativo Java que fornece um modelo de programação de fluxo de dados declarativo baseado em fluxo para programação assíncrona orientada por eventos. O createDocumentsIfNotExist implementa a programação assíncrona do Project Reactor.

No createUserDocumentsIfNotExist, Flux.fromIterable(users) é um método de fábrica do Project Reactor. Ele cria uma instância Flux que é uma fonte de eventos assíncronos. Nesse caso, cada "evento" assíncrono inclui um argumento de instância User. A instância Flux contém dois eventos desse tipo, um para maxaxam e outro para nelapin. O código dentro de .flatMap( ... ).blockLast(); define um pipeline de operações sequenciais a serem executadas nos eventos emitidos pela instância Flux.

Uma dessas operações é createItem. A ideia é que esse pipeline seja quase idêntico à implementação síncrona, exceto pelo fato de a chamada createItem não estar bloqueada. Especificamente, a chamada para blockLast() assina o pipeline montado, fazendo com que o Flux emita de modo assíncrono dois eventos. Em seguida, o pipeline dentro de .flatMap( ... ).blockLast(); processa cada um desses eventos de maneira pseudoparalela. Quando uma solicitação for emitida e aguardar uma resposta, o Project Reactor processará outras solicitações em segundo plano, o que é o fator crítico para maximizar as solicitações/segundo por thread.

Agora que demonstramos as solicitações de banco de dados assíncronas eficientes com o Project Reactor, no restante deste laboratório usaremos chamadas de bloqueio (sincronização) para maior simplicidade. Para saber mais sobre o Project Reactor, confira Guia de padrões do Reactor do Azure Cosmos DB.

Ler documentos

  1. Para ler documentos do banco de dados, adicione o seguinte método a CosmosApp:

    /**
     * Take in a Java POJO argument, extract ID and partition key, and read the corresponding document from the container.
     * In this case the ID is the partition key.
     * @param user User POJO to pull ID and partition key from.
     */
    private static CosmosItemResponse<User> readUserDocument(final User user) {
        CosmosItemResponse<User> userReadResponse = null;
    
        try {
            userReadResponse = container.readItem(user.getId(), new PartitionKey(user.getUserId()), User.class).block();
            logger.info("Read user {}", user.getId());
        } catch (CosmosException de) {
            logger.error("Failed to read user {}", user.getId(), de);
        }
    
        return userReadResponse;
    }
    
  2. Copie e cole o seguinte código ao final do método basicOperations, após o código de criação de documento:

    readUserDocument(maxaxam);
    
  3. Crie e execute o CosmosApp.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
    

    O terminal exibe a saída a seguir, em que "Read user 1" indica que o documento foi recuperado.

    INFO: Database and container validation complete
    INFO: User 1 already exists in the database
    INFO: User 2 already exists in the database
    INFO: Read user 1
    

    Você também poderá ver um texto adicional emitido pelo agente.

Substituir documentos

O Azure Cosmos DB dá suporte à substituição de documentos JSON. Nesse caso, atualizaremos um registro de usuário para levar em conta uma alteração em seu sobrenome.

  1. Adicione o método replaceUserDocument após o método readUserDocument no arquivo CosmosApp.java.

    /**
     * Take in a Java POJO argument, extract ID and partition key,
     * and replace the existing document with the same ID and partition key to match.
     * @param user User POJO representing the document update.
     */
    private static void replaceUserDocument(final User user) {
        try {
            CosmosItemResponse<User> userReplaceResponse = container.replaceItem(user, user.getId(), new PartitionKey(user.getUserId())).block();
            logger.info("Replaced User {}", user.getId());
        } catch (CosmosException de) {
            logger.error("Failed to replace User {}", user.getUserId());
        }
    }
    
  2. Copie e cole o código a seguir ao final do método basicOperations, após o código de leitura do documento.

    maxaxam.setLastName("Suh");
    replaceUserDocument(maxaxam);
    
  3. Crie e execute o CosmosApp.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
    

    O terminal exibe a saída a seguir, em que "Replaced last name for Suh" indica que o documento foi substituído.

    INFO: Database and container validation complete
    INFO: User 1 already exists in the database
    INFO: User 2 already exists in the database
    INFO: Read user 1
    INFO: Replaced last name for Suh
    

Excluir documentos

  1. Copie e cole o método deleteUserDocument no seu método replaceUserDocument.

    /**
     * Take in a Java POJO argument, extract ID and partition key,
     * and delete the corresponding document.
     * @param user User POJO representing the document update.
     */
    private static void deleteUserDocument(final User user) {
        try {
            container.deleteItem(user.getId(), new PartitionKey(user.getUserId())).block();
            logger.info("Deleted user {}", user.getId());
        } catch (CosmosException de) {
            logger.error("User {} could not be deleted.", user.getId());
        }
    }
    
  2. Copie e cole o código a seguir ao final do método basicOperations.

    deleteUserDocument(maxaxam);
    
  3. Crie e execute o CosmosApp.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
    

    O terminal exibe a saída a seguir, em que "Deleted user 1" indica que o documento foi excluído.

    INFO: Database and container validation complete
    INFO: User 1 already exists in the database
    INFO: User 2 already exists in the database
    INFO: Read User 1
    INFO: Replaced last name for Suh
    INFO: Deleted User 1
    

Trabalhando com documentos de forma programática

Os dados são armazenados em documentos JSON no Azure Cosmos DB. Os documentos podem ser criados, recuperados, substituídos ou excluídos no portal ou programaticamente. Este laboratório se concentra em operações programáticas. Todas essas operações estão disponíveis no SDK do Java do Azure Cosmos DB e também podem ser acessadas por meio do modelo de programação do Spring Data. Neste módulo, usaremos o Spring Data para Azure Cosmos DB a fim de executar operações CRUD (criar, recuperar, atualizar e excluir) nos dados NoSQL armazenados no Azure Cosmos DB.

As principais operações em documentos do Spring Data para Azure Cosmos DB são operações básicas no modelo de programação do Spring Data:

  • save – escreva ou atualize um documento, dependendo do fato de o documento já existir ou não.
  • view – leia um documento
  • delete– exclua um documento

Para executar qualquer uma dessas operações, você precisará de classes auxiliares (classes POJO do Java) que representam os objetos armazenados no banco de dados. Como estamos trabalhando com um banco de dados de clientes online, convém usar a classe WebCustomer para representar as entidades do usuário. Essa classe armazenará dados primários, como nome, sobrenome e ID de usuário. (A ID é necessária porque ela é a chave de partição para habilitar a escala horizontal.)

Cada cliente da Web tem algumas preferências de envio e cupons associados a ele, portanto, convém que os tipos de dados ShippingPreference e CouponsUsed representem essas entidades também. Por fim, cada cliente da Web pode ter algum histórico de pedidos desassociado, portanto, é recomendável ter entidades OrderHistory separadas com uma classe POJO do Java correspondente.

Vá para src/main/java/com/azure/cosmos/examples/springexamples. Você verá o POJO WebCustomer. Agora, procure na pasta common. Você verá vários POJOs:ShippingPreference, OrderHistory e CouponsUsed. Portanto, fornecemos todos os POJOs de entidade e as classes auxiliares deles.

Em seguida, criaremos algumas entidades e realizaremos algumas operações CRUD básicas no contêiner do Azure Cosmos DB e nos documentos que ele contém. Você pode passar para o Azure Cosmos DB um ObjectNode do Jackson que especifica diretamente o documento JSON. Entretanto, o Azure Cosmos DB também é capaz de serializar POJOs do Java em JSON, e recomendamos essa abordagem como a opção mais simples (caso o restante seja igual).

Criar e atualizar documentos

  1. Abra WebCustomer.java e examine o conteúdo. Ele deverá ser semelhante a este:

    // Copyright (c) Microsoft Corporation. All rights reserved.
    // Licensed under the MIT License.
    package com.azure.cosmos.examples.springexamples;
    
    import com.azure.cosmos.examples.springexamples.common.CouponsUsed;
    import com.azure.cosmos.examples.springexamples.common.OrderHistory;
    import com.azure.cosmos.examples.springexamples.common.ShippingPreference;
    import com.azure.spring.data.cosmos.core.mapping.Container;
    import com.azure.spring.data.cosmos.core.mapping.PartitionKey;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.List;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Container(containerName = "WebCustomer", ru = "400")
    public class WebCustomer {
    
        /** Document ID (required by Azure Cosmos DB). */
        private String id;
    
        /** WebCustomer ID. */
        private String userId;
    
        /** WebCustomer last name. */
        @PartitionKey
        private String lastName;
    
        /** WebCustomer first name. */
        private String firstName;
    
        /** WebCustomer email address. */
        private String email;
    
        /** WebCustomer dividend setting. */
        private String dividend;
    
        /** WebCustomer shipping preferences. */
        private ShippingPreference shippingPreference;
    
        /** WebCustomer order history. */
        private List<OrderHistory> orderHistory;
    
        /** Coupons recorded by the user. */
        private List<CouponsUsed> coupons;
    }
    

    Observe que os métodos de acesso aos campos iduserId e outros são implícitos (não definidos no código). Esse comportamento é possível porque usamos a anotação @Data do Project Lombok para criá-los automaticamente.

    A anotação @NoArgsConstructor gerará um construtor sem argumentos que define valores de campo padrão. A anotação @AllArgsConstructor gerará outro construtor com um conjunto completo de argumentos para especificar todos os valores de campo diretamente.

    Observe que WebCustomer tem uma propriedade id. Todos os documentos do Azure Cosmos DB exigem uma propriedade id, portanto, todos os POJOs que pretendemos serializar em documentos JSON precisam ter um campo id.

  2. Adicione o seguinte método a CosmosSample.java:

    /**
     * Take in list of Java POJOs and insert them into the database.
     * @param webCustomers List of WebCustomer POJOs to insert.
     */
    private void createWebCustomerDocumentsIfNotExist(final List<WebCustomer> webCustomers) {
        Flux.fromIterable(webCustomers).flatMap(webCustomer -> {
            logger.info("Creating WebCustomer {}", webCustomer.getId());
            return this.reactiveWebCustomerRepository.save(webCustomer);
        }).blockLast();
    }
    
  3. Encontre o método run e adicione o código a seguir ao final dele.

    WebCustomer maxaxam = new WebCustomer(
            "1",
            "maxaxam",
            "Axam",
            "Max",
            "maxaxam@contoso.com",
            "2.0",
            new ShippingPreference(
                    1,
                    "90 W 8th St",
                    "",
                    "New York",
                    "NY",
                    "10001",
                    "USA"
            ),
            new ArrayList<OrderHistory>(Arrays.asList(
                    new OrderHistory(
                            "3",
                            "1000",
                            "08/17/2018",
                            "52.49"
                    )
            )),
            new ArrayList<CouponsUsed>(Arrays.asList(
                    new CouponsUsed(
                            "A7B89F"
                    )
            ))
    );
    
    WebCustomer nelapin = new WebCustomer(
            "2",
            "nelapin",
            "Pindakova",
            "Nela",
            "nelapin@contoso.com",
            "8.50",
            new ShippingPreference(
                    1,
                    "505 NW 5th St",
                    "",
                    "New York",
                    "NY",
                    "10001",
                    "USA"
            ),
            new ArrayList<OrderHistory>(Arrays.asList(
                    new OrderHistory(
                            "4",
                            "1001",
                            "08/17/2018",
                            "105.89"
                    )
            )),
            new ArrayList<CouponsUsed>(Arrays.asList(
                    new CouponsUsed(
                            "Fall 2018"
                    )
            ))
    );
    
    createWebCustomerDocumentsIfNotExist(new ArrayList(Arrays.asList(maxaxam, nelapin)));
    
  4. Compile e execute o CosmosSample.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, você deve ver

    INFO: Creating WebCustomer 1
    INFO: Creating WebCustomer 2
    

Parabéns! Você criou e/ou atualizou seus primeiros dados no Azure Cosmos DB usando um aplicativo Java. Vamos pausar e avaliar o que você fez aqui.

Em run, há três novas ações:

  1. Criar/atualizar a instância maxaxam WebCustomer.
  2. Criar/atualizar a instância nelapin WebCustomer.
  3. Chamar createWebCustomerDocumentsIfNotExist, passando maxaxam e nelapin em uma lista.

Chamar createWebCustomerDocumentsIfNotExist insere as duas instâncias de WebCustomer como itens/documentos no Azure Cosmos DB. Quando você passa as instâncias de WebCustomer como uma lista, nossa intenção é modelar um método de alto desempenho para ingerir POJOs rapidamente no Azure Cosmos DB, usando recursos de computação mínimos. O createWebCustomerDocumentsIfNotExist implementa a inserção assíncrona eficiente de uma lista de POJOs. Se o documento já existir, save realizará uma atualização em vez de criar um documento.

Suponha que a nossa meta seja maximizar solicitações/segundo por thread. Para fins de comparação, a abordagem de sincronização para gravar createWebCustomerDocumentsIfNotExist seria iterar cada instância de WebCustomer em webCustomers. Para cada WebCustomer webCustomer, faríamos uma chamada de bloqueio para save:

this.reactiveWebCustomerRepository.save(webCustomer).block(); // <= Note the .block() which loops until request response.

Esse estilo de sincronização implementa um processo intuitivo: emitir a solicitação, aguardar a resposta, emitir a próxima solicitação. No entanto, o createWebCustomerDocumentsIfNotExist não usa essa abordagem porque as chamadas de bloqueio causarão essencialmente um desperdício dos ciclos de CPU durante o tempo de resposta da solicitação, fazendo com que haja um volume baixo de solicitações/segundo.

Você pode contornar esse problema de solicitações/segundo gerando vários threads para fazer chamadas de solicitação de bloqueio em paralelo. Vários threads resultarão em um aprimoramento do tempo de execução. No entanto, se a sua meta for economizar recursos de thread, isso ainda será um desperdício. Cada thread executa loops durante o tempo de resposta da solicitação, quando poderia estar realizando multitarefa para outro item, o que resulta em um volume baixo de solicitações/segundo por thread.

Por esse motivo e para mostrar a você a inserção eficiente de threads de POJOs do Java, fornecemos, em vez disso, um exemplo assíncrono de inserção de documento. O suporte assíncrono do Spring Data é proveniente do Project Reactor, uma estrutura de aplicativo Java que fornece um modelo de programação de fluxo de dados declarativo baseado em fluxo para programação assíncrona orientada por eventos. O createWebCustomerDocumentsIfNotExist implementa a programação assíncrona do Project Reactor.

No createWebCustomerDocumentsIfNotExist, Flux.fromIterable(webCustomers) é um método de fábrica do Project Reactor. Ele cria uma instância Flux que é uma fonte de eventos assíncronos. Nesse caso, cada "evento" assíncrono inclui um argumento de instância WebCustomer. A instância Flux contém dois eventos desse tipo, um para maxaxam e outro para nelapin. O código dentro de .flatMap( ... ).blockLast(); define um pipeline de operações sequenciais a serem executadas nos eventos emitidos pela instância Flux.

Nesse caso, as duas operações no pipeline são chamadas save. A ideia é que esse pipeline seja quase idêntico à implementação síncrona, exceto pelo fato de a chamada save não estar bloqueada. Especificamente, a chamada para blockLast() assina o pipeline montado, fazendo com que o Flux emita de modo assíncrono dois eventos. Em seguida, o pipeline dentro de .flatMap( ... ).blockLast(); processa cada um desses eventos de maneira pseudoparalela. Quando uma solicitação for emitida e aguardar uma resposta, o Project Reactor processará outras solicitações em segundo plano, o que é o fator crítico para maximizar as solicitações/segundo por thread.

Agora que demonstramos solicitações de banco de dados assíncronas eficientes com o Project Reactor, no restante deste laboratório usaremos chamadas de bloqueio assíncronas (chamadas de sincronização efetivas) para maior simplicidade. Para saber mais sobre o Project Reactor, confira Guia de padrões do Reactor do Azure Cosmos DB.

Ler documentos

  1. Para ler documentos do banco de dados, adicione o seguinte método a CosmosSample:

    /**
     * Take in a Java POJO argument, extract ID and partition key, and read the corresponding document from the container.
     * In this case the ID is the partition key.
     * @param webCustomer User POJO to pull ID and partition key from.
     */
    private WebCustomer readWebCustomerDocument(final WebCustomer webCustomer) {
        WebCustomer webCustomerResult = null;
    
        try {
            logger.info("Read webCustomer {}", webCustomer.getId());
            webCustomerResult = this.reactiveWebCustomerRepository.findById(webCustomer.getId(), new PartitionKey(webCustomer.getLastName())).block();
        } catch (CosmosException de) {
            logger.error("Failed to read webCustomer {}", webCustomer.getId(), de);
        }
    
        return webCustomer;
    }
    
  2. Copie e cole o seguinte código ao final do método run, após o código de criação de documento:

    readWebCustomerDocument(maxaxam);
    
  3. Compile e execute o CosmosSample.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, você deve ver os itens a seguir. "Read user 1" indica que o documento foi recuperado.

    INFO: Read webCustomer 1
    

Excluir documentos

  1. Copie e cole o método deleteWebCustomerDocument no seu método readWebCustomerDocument.

    /**
     * Take in a Java POJO argument, extract ID and partition key,
     * and delete the corresponding document.
     * @param webCustomer User POJO representing the document update.
     */
    private void deleteWebCustomerDocument(final WebCustomer webCustomer) {
        try {
            this.reactiveWebCustomerRepository.deleteById(webCustomer.getId(),new PartitionKey(webCustomer.getLastName())).block();
            logger.info("Deleted webCustomer {}", webCustomer.getId());
        } catch (CosmosException de) {
            logger.error("User {} could not be deleted.", webCustomer.getId());
        }
    }
    
  2. Copie e cole o código a seguir ao final do método run.

    deleteWebCustomerDocument(maxaxam);
    
  3. Compile e execute o CosmosSample.java no IDE ou execute o programa no terminal usando:

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, você deve ver os itens a seguir. "Deleted user 1" indica que o documento foi excluído.

    INFO: Deleted webCustomer 1
    

Nesta unidade, você criou, atualizou, leu e excluiu documentos no banco de dados do Azure Cosmos DB.