Exercício – criar, ler, atualizar e eliminar dados NoSQL de forma programática

Concluído

Estabeleceu a ligação ao Azure Cosmos DB. Nesta unidade, vai criar documentos do utilizador na sua coleção WebCustomers. Em seguida, vai obter esses documentos por ID, substituí-los e eliminá-los.

Trabalhar com documentos através de programação

Os dados são armazenados em documentos JSON no Azure Cosmos DB. Os documentos podem ser criados, obtidos, substituídos ou eliminados no portal ou de forma programática. Este laboratório foca-se nas operações programáticas. O Azure Cosmos DB disponibiliza SDKs no lado do cliente para .NET, .NET Core, Java, Node.js e Python, cada um deles suporta estas operações. Neste módulo, vamos utilizar o SDK Java para executar operações CRUD (criar, obter, atualizar e eliminar) nos dados armazenados NoSQL no Azure Cosmos DB.

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

O método Upsert executa uma operação de criação ou substituição, dependendo se o documento já existe.

Para realizar qualquer uma destas operações, precisará de classes de programa auxiliar (classes POJO Java) que representam os objetos armazenados na base de dados. Uma vez que estamos a trabalhar com uma base de dados de utilizadores, é recomendável ter uma classe User que represente as entidades dos utilizadores. Esta classe irá armazenar dados primários, como o nome próprio, apelido e ID de utilizador. (O ID é necessário, uma vez que se trata da chave da partição para permitir o dimensionamento horizontal.)

Cada utilizador tem preferências de envio e cupões associados, pelo que é recomendável que os tipos de dados ShippingPreference e CouponsUsed representem essas entidades. Por fim, cada utilizador pode ter um histórico de encomendas que seja potencialmente não vinculado, pelo que é recomendável ter entidades OrderHistory diferentes com uma classe POJO Java correspondente.

Aceda a src/main/java/com/azure/azure-cosmos-java-sql-app-mslearn e analise a pasta datatypes. Verá vários POJOs: User, ShippingPreference, OrderHistory e CouponsUsed. Como tal, fornecemos todos os POJOs da entidade e as respetivas classes de programa auxiliar.

Em seguida, iremos criar algumas entidades e realizar algumas operações CRUD básicas no contentor do Azure Cosmos DB e nos documentos contidos no mesmo. Pode transmitir ao Azure Cosmos DB uma instância ObjectNode Jackson que especifica diretamente o documento JSON. No entanto, o Azure Cosmos DB também consegue serializar POJOs Java em JSON. Recomendamos esta abordagem como a opção mais simples (tudo o resto é igual).

Criar documentos

  1. Abra User.java e examine o conteúdo. Deve ter um aspeto semelhante a:

    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 dos campos id e userId, entre outros, são implícitos (não definidos no código). Este comportamento é possível porque utilizamos a anotação @Data de Project Lombok para os criar automaticamente.

    A anotação @NoArgsConstructor irá criar um construtor sem argumentos que predefine os valores dos campos. A anotação @AllArgsConstructor irá criar outro construtor com uma lista completa de argumentos para especificar diretamente todos os valores dos campos.

    Tenha em atenção que User tem uma propriedade id. Todos os documentos do Azure Cosmos DB necessitam da propriedade id. Como tal, todos os POJOs que pretendemos serializar em documentos JSON têm de 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. Volte ao método basicOperations e adicione o seguinte à parte final desse método, 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 CosmosApp.java no IDE ou execute o programa no terminal com:

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

    O terminal apresentará o resultado à medida que a aplicação cria cada novo documento de utilizador.

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

    Pode ver texto adicional emitido pelo logger, como carimbos de data/hora.

Parabéns! Criou os seus primeiros dados no Azure Cosmos DB a partir de uma aplicação Java. Vamos pausar e avaliar o que fez.

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

  1. Crie a instância maxaxamUser .
  2. Crie a instância de nelapinUser .
  3. Chamar createUserDocumentsIfNotExist, transmitindo maxaxam e nelapin numa lista.

A chamada de createUserDocumentsIfNotExist introduz as instâncias User como itens/documentos no Azure Cosmos DB. Quando transmite as instâncias User como uma lista, a nossa intenção é criar um modelo de desempenho para a ingestão rápida de POJOs no Azure Cosmos DB, com o mínimo de recursos de computação. createUserDocumentsIfNotExist implementa uma inserção assíncrona e eficiente de uma lista de POJOs.

Suponha que o nosso objetivo consiste em maximizar os pedidos/segundo por thread. Para uma questão de comparação, a abordagem de sincronização para escrever createUserDocumentsIfNotExist (ignorando por um momento a verificação readItem) seria a iteração sobre cada instância User em users. Para cada Useru, 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.

Este estilo de sincronização implementa um processo intuitivo: emitir pedido, aguardar a resposta, emitir novo pedido. No entanto, createUserDocumentsIfNotExist não utiliza esta abordagem, uma vez que as chamadas de bloqueio irão essencialmente desperdiçar ciclos da CPU durante o tempo de resposta do pedido, causando uma taxa baixa de pedidos/segundo.

Pode contornar este problema de pedidos/segundo ao gerar múltiplos threads para realizar chamadas de pedidos de bloqueio paralelas. Os múltiplos threads causarão uma melhoria no tempo de execução. No entanto, se o objetivo for ser prudente com os recursos dos threads, isto continuaria a ser ineficaz, Cada thread é repetido continuamente durante o tempo de resposta do pedido quando podia fazer multitasking, ao proporcionar uma taxa baixa de pedidos/segundo por thread.

Por este motivo e para a finalidade de mostrar uma inserção eficiente nos threads de POJOs Java, fornecemos um exemplo assíncrono de inserção de documentos. O suporte assíncrono v4 do SDK Java do Azure Cosmos DB tem origem no Project Reactor, uma estrutura de aplicação Java que fornece um modelo de programação de fluxo de dados declarativo com base nas transmissões para a programação assíncrona baseada em eventos. createDocumentsIfNotExist implementa a programação assíncrona do Project Reactor.

Em createUserDocumentsIfNotExist, Flux.fromIterable(users) é um método de fábrica do Project Reactor. Cria uma instância Flux que é uma origem de eventos assíncronos. Neste caso, cada “evento” assíncrono inclui um argumento de instância User. A instância Flux contém dois eventos semelhantes: um para maxaxam e outro para nelapin. O código em .flatMap( ... ).blockLast(); define um pipeline de operações sequenciais a serem realizadas nos eventos emitidos pela instância Flux.

Uma dessas operações é createItem. A ideia é que este pipeline é quase idêntico à implementação síncrona, com a exceção de não se registar um bloqueio na chamada createItem. Especificamente, a chamada para blockLast()se inscrever no pipeline montado, fazendo com que o emita de forma assíncrona Flux seus dois eventos. Depois, o pipeline em .flatMap( ... ).blockLast(); processa cada um desses eventos de forma pseudo-paralela. Quando um pedido é emitido e aguarda a resposta, o Project Reactor processará outros pedidos em segundo plano, que é o fator crítico na maximização de pedidos/segundo por thread.

Agora que demonstrámos pedidos de base de dados assíncronos e eficientes com o Project Reactor, no resto do laboratório serão utilizadas chamadas de bloqueio (de sincronização) por uma questão de simplicidade. Para saber mais sobre o Project Reactor, veja o Guia de Padrões do Reactor do Azure Cosmos DB.

Ler documentos

  1. Para ler documentos da base 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 à parte final do método basicOperations, após o código de criação de documentos:

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

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

    O terminal apresenta o seguinte resultado, no qual “Foi lido o utilizador 1” indica que o documento foi obtido.

    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
    

    Também pode ver texto adicional emitido pelo logger.

Substituir documentos

O Azure Cosmos DB suporta a substituição de documentos JSON. Neste caso, vamos atualizar um registo de utilizador para considerar uma alteração nos apelidos.

  1. Adicione o método replaceUserDocument após o método readUserDocument no ficheiro 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 no final do método, após o documento ler o basicOperations código.

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

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

    O terminal apresenta o seguinte resultado, no qual “Substituído apelido para 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
    

Eliminar 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 seguinte código à parte final do método basicOperations.

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

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

    O terminal apresenta o resultado seguinte, no qual “Foi eliminado o utilizador 1” indica que o documento foi eliminado.

    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
    

Trabalhar com documentos através de programação

Os dados são armazenados em documentos JSON no Azure Cosmos DB. Os documentos podem ser criados, obtidos, substituídos ou eliminados no portal ou de forma programática. Este laboratório foca-se nas operações programáticas. Todas essas operações estão disponíveis no SDK Java do Azure Cosmos DB e também podem ser acessadas por meio do modelo de programação Spring Data. Neste módulo, vamos utilizar o Azure Cosmos DB do Spring Data para executar operações CRUD (criar, obter, atualizar e eliminar) nos dados armazenados NoSQL no Azure Cosmos DB.

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

  • save – aponte-escreva ou atualize um documento, dependendo se o documento já existe.
  • view – aponte-leia um documento
  • delete – aponte-elimine um documento

Para realizar qualquer uma destas operações, precisará de classes de programa auxiliar (classes POJO Java) que representam os objetos armazenados na base de dados. Uma vez que estamos a trabalhar com uma base de dados de clientes online, é recomendável ter uma classe WebCustomer que represente as entidades dos utilizadores. Esta classe irá armazenar dados primários, como o nome próprio, apelido e ID de utilizador. (O ID é necessário, uma vez que se trata da chave da partição para permitir o dimensionamento horizontal.)

Cada cliente Web tem preferências de envio e cupões associados, pelo que é recomendável que os tipos de dados ShippingPreference e CouponsUsed representem essas entidades. Por fim, cada cliente Web pode ter um histórico de encomendas que seja potencialmente não vinculado, pelo que é recomendável ter entidades OrderHistory diferentes com uma classe POJO Java correspondente.

Aceda a src/main/java/com/azure/cosmos/examples/springexamples. Verá o POJO WebCustomer. Agora, procure na pasta comum. Verá vários POJOs: ShippingPreference, OrderHistory e CouponsUsed. Como tal, fornecemos todos os POJOs da entidade e as respetivas classes de programa auxiliar.

Em seguida, iremos criar algumas entidades e realizar algumas operações CRUD básicas no contentor do Azure Cosmos DB e nos documentos contidos no mesmo. Pode transmitir ao Azure Cosmos DB uma instância ObjectNode Jackson que especifica diretamente o documento JSON. No entanto, o Azure Cosmos DB também consegue serializar POJOs Java em JSON. Recomendamos esta abordagem como a opção mais simples (tudo o resto é igual).

Criar e atualizar documentos

  1. Abra WebCustomer.java e examine o conteúdo. Deve ter um aspeto semelhante a:

    // 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 dos campos id e userId, entre outros, são implícitos (não definidos no código). Este comportamento é possível porque utilizamos a anotação @Data de Project Lombok para os criar automaticamente.

    A anotação @NoArgsConstructor irá criar um construtor sem argumentos que predefine os valores dos campos. A anotação @AllArgsConstructor irá criar outro construtor com uma lista completa de argumentos para especificar diretamente todos os valores dos campos.

    Tenha em atenção que WebCustomer tem uma propriedade id. Todos os documentos do Azure Cosmos DB necessitam da propriedade id. Como tal, todos os POJOs que pretendemos serializar em documentos JSON têm de 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. Localize o método run e adicione o seguinte código à parte final desse método.

    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. Crie e execute CosmosSample.java no IDE ou execute o programa no terminal com:

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, deverá ver

    INFO: Creating WebCustomer 1
    INFO: Creating WebCustomer 2
    

Parabéns! Criou e/ou atualizou os primeiros dados no Azure Cosmos DB a partir de uma aplicação Java. Vamos pausar e avaliar o que fez.

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

  1. Crie/atualize a instância maxaxamWebCustomer.
  2. Crie/atualize a instância de nelapinWebCustomer .
  3. Chamar createWebCustomerDocumentsIfNotExist, transmitindo maxaxam e nelapin numa lista.

A chamada de createWebCustomerDocumentsIfNotExist introduz as instâncias WebCustomer como itens/documentos no Azure Cosmos DB. Quando transmite as instâncias WebCustomer como uma lista, a nossa intenção é criar um modelo de desempenho para a ingestão rápida de POJOs no Azure Cosmos DB, com o mínimo de recursos de computação. createWebCustomerDocumentsIfNotExist implementa uma inserção assíncrona e eficiente de uma lista de POJOs. Se o documento já existir, save executará uma atualização em vez de criar um documento.

Suponha que o nosso objetivo consiste em maximizar os pedidos/segundo por thread. Para comparação, a abordagem de sincronização para escrever createWebCustomerDocumentsIfNotExist seria a iteração sobre cada instância WebCustomer em webCustomers. Para cada WebCustomerwebCustomer, faríamos uma chamada de bloqueio para save:

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

Este estilo de sincronização implementa um processo intuitivo: emitir pedido, aguardar a resposta, emitir novo pedido. No entanto, createWebCustomerDocumentsIfNotExist não utiliza esta abordagem, uma vez que as chamadas de bloqueio irão essencialmente desperdiçar ciclos da CPU durante o tempo de resposta do pedido, causando uma taxa baixa de pedidos/segundo.

Pode contornar este problema de pedidos/segundo ao gerar múltiplos threads para realizar chamadas de pedidos de bloqueio paralelas. Os múltiplos threads causarão uma melhoria no tempo de execução. No entanto, se o objetivo for ser prudente com os recursos dos threads, isto continuaria a ser ineficaz, Cada thread é repetido continuamente durante o tempo de resposta do pedido quando podia fazer multitasking, ao proporcionar uma taxa baixa de pedidos/segundo por thread.

Por este motivo e para a finalidade de mostrar uma inserção eficiente nos threads de POJOs Java, fornecemos um exemplo assíncrono de inserção de documentos. O suporte assíncrono do Spring Data tem origem no Project Reactor, uma estrutura de aplicação Java que proporciona um modelo de programação de fluxo de dados declarativo com base nas transmissões para a programação assíncrona baseada em eventos. createWebCustomerDocumentsIfNotExist implementa a programação assíncrona do Project Reactor.

Em createWebCustomerDocumentsIfNotExist, Flux.fromIterable(webCustomers) é um método de fábrica do Project Reactor. Cria uma instância Flux que é uma origem de eventos assíncronos. Neste caso, cada “evento” assíncrono inclui um argumento de instância WebCustomer. A instância Flux contém dois eventos semelhantes: um para maxaxam e outro para nelapin. O código em .flatMap( ... ).blockLast(); define um pipeline de operações sequenciais a serem realizadas nos eventos emitidos pela instância Flux.

Neste caso, as duas operações no pipeline são chamadas save. A ideia é que este pipeline é quase idêntico à implementação síncrona, com a exceção de não se registar um bloqueio na chamada save. Especificamente, a chamada para blockLast()se inscrever no pipeline montado, fazendo com que o emita de forma assíncrona Flux seus dois eventos. Depois, o pipeline em .flatMap( ... ).blockLast(); processa cada um desses eventos de forma pseudo-paralela. Quando um pedido é emitido e aguarda a resposta, o Project Reactor processará outros pedidos em segundo plano, que é o fator crítico na maximização de pedidos/segundo por thread.

Agora que demonstrámos os pedidos de base de dados assíncronos e eficientes com o Project Reactor, no resto do laboratório serão utilizadas chamadas assíncronas de bloqueio (chamadas de sincronização) por uma questão de simplicidade. Para saber mais sobre o Project Reactor, veja o Guia de Padrões do Reactor do Azure Cosmos DB.

Ler documentos

  1. Para ler documentos da base 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 à parte final do método run, após o código de criação de documentos:

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

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, deverá ver o seguinte. “Utilizador 1 de leitura” indica que o documento foi recuperado.

    INFO: Read webCustomer 1
    

Eliminar 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 seguinte código à parte final do método run.

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

    mvn clean package
    mvn spring-boot:run
    

    Na saída do terminal, deverá ver o seguinte. “Utilizador 1 eliminado ” indica que o documento foi eliminado.

    INFO: Deleted webCustomer 1
    

Nesta unidade, criou, atualizou, leu e eliminou documentos na base de dados do Azure Cosmos DB.