Exercice : Créer, lire, mettre à jour et supprimer des données NoSQL par programmation

Effectué

Vous avez exécuté la connexion sur Azure Cosmos DB. Dans cette unité, vous allez créer des documents utilisateur dans votre collection WebCustomers. Ensuite, vous récupérerez les documents d’après leur ID, vous les remplacerez et vous les supprimerez.

Utiliser des documents par programme

Dans Azure Cosmos DB, les données sont stockées dans des documents JSON. Les documents peuvent être créés, récupérés, remplacés ou supprimés dans le portail ou programmatiquement. Ce labo se concentre sur les opérations de programmation. Azure Cosmos DB fournit des kits SDK côté client pour les langages .NET, .NET Core, Java, Node.js et Python, qui prennent tous en charge ces opérations. Dans ce module, nous allons utiliser le kit de développement logiciel (SDK) Java pour effectuer des opérations CRUD (création, récupération, mise à jour et suppression) sur les données stockées NoSQL dans Azure Cosmos DB.

Pour les documents Azure Cosmos DB, les principales opérations font partie de la classe CosmosAsyncContainer :

Upsert exécute une opération de création ou de remplacement, en fonction de l’existence ou pas du document.

Pour effectuer une de ces opérations, vous aurez besoin de classes d’assistance (classes Java POJO) qui représentent les objets stocks dans la base de données. Étant donné que nous travaillons avec une base de données d’utilisateurs, vous devrez disposer d’une classe User représentant les entités utilisateur. Cette classe stocke les données principales, telles que le prénom, le nom et l’ID utilisateur. (L’ID est obligatoire, car il s’agit de la clé de partition pour activer la mise à l’échelle horizontale.)

Chaque utilisateur possède des préférences et des coupons d’expédition associés, vous souhaiterez donc que les types de données ShippingPreference et CouponsUsed représentent ces entités. Enfin, chaque utilisateur peut avoir un historique des commandes qui ne lui est pas associé. Il est donc préférable d’avoir des entités OrderHistory séparées, avec une classe Java POJO correspondante.

Accédez à src/main/Java/com/Azure/Azure-Cosmos-Java-SQL-App-mslearn et recherchez dans le dossier types de données. Vous verrez plusieurs POJO : User, ShippingPreference, OrderHistory et CouponsUsed. Nous avons donc fourni toutes les classes POJO d’entités avec leurs classes d’assistance !

Ensuite, nous allons créer des entités et effectuer des opérations CRUD de base sur le conteneur Azure Cosmos DB et les documents qu’il contient. Vous pouvez transmettre à Azure Cosmos DB une instance ObjectNode qui spécifie directement le document JSON. Mais, Azure Cosmos DB peut également sérialiser des classes POJO Java en documents JSON. Il s’agit d’ailleurs de l’approche que nous recommandons car elle est la plus simple (les autres sont équivalentes).

Créer des documents

  1. Ouvrez User.java et examinez son contenu. Il doit se présenter comme suit :

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

    Notez que les méthodes d’accès aux champs id, userId et d’autres champs sont implicites (c’est-à-dire, non définies dans le code). Ce comportement est possible, car nous utilisons l’annotation@Data Project Lombok pour les créer automatiquement.

    L’annotation @NoArgsConstructor génère un constructeur sans argument qui définit les valeurs de champ par défaut. L’annotation @AllArgsConstructor génère un autre constructeur avec un ensemble complet d’arguments pour spécifier toutes les valeurs de champ directement.

    Notez que User a une propriété id. Tous les documents Azure Cosmos DB nécessitent une propriété id. Il est donc nécessaire que toutes les classes POJO que nous avons l’intention de sérialiser en documents JSON aient un champ id.

  2. Ajoutez la méthode suivante à 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. Revenez à la méthode basicOperations, puis ajoutez ce qui suit à la fin de cette méthode, avant l’appel 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. Générez et exécutez CosmosApp.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

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

    Le terminal affiche la sortie lorsque l’application crée chaque document du nouvel utilisateur.

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

    Vous pouvez également voir du texte supplémentaire émis par l’enregistreur d’événements, notamment des timestamps.

Félicitations ! Vous avez créé vos premières données dans Azure Cosmos DB à partir d’une application Java. Faisons une pause pour comprendre ce que vous venez de faire.

Dans basicOperations, il existe trois nouvelles actions :

  1. Créez l’instance maxaxam User.
  2. Créez l’instance nelapin User.
  3. Appelez createUserDocumentsIfNotExist, en passant par maxaxam et nelapin dans une liste.

L’appel de createUserDocumentsIfNotExist insère les deux instances User en tant qu’éléments/documents dans Azure Cosmos DB. En vous faisant passer les instances User sous la forme d’une liste, notre objectif est de modéliser une méthode performante pour la réception rapide de classes POJO dans Azure Cosmos DB, à l’aide de ressources de calcul minimales. createUserDocumentsIfNotExist implémente l’insertion asynchrone efficace d’une liste de classes POJO.

Supposons que notre objectif soit de maximiser le nombre de requêtes par seconde dans chaque thread. En comparaison, l’approche de synchronisation appliquée à l’écriture de createUserDocumentsIfNotExist (en ignorant pour le moment la vérification readItem) consiste à itérer au sein de chaque instance User de users. Pour chaque Useru, nous allons faire un appel de blocage pour createItem :

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

Ce style de synchronisation implémente un processus intuitif : envoyer la requête, attendre la réponse, envoyer la requête suivante. Toutefois, createUserDocumentsIfNotExist n’utilise pas cette approche, car les appels de blocage gaspillent les cycles du processeur pendant le temps de réponse de la requête, ce qui entraîne un faible taux de requêtes par seconde.

Vous pouvez contourner ce problème de requêtes par seconde en générant plusieurs threads afin d’effectuer des appels de requête de blocage parallèles. Les threads multiples entraînent une amélioration de la durée d’exécution. Toutefois, si votre objectif est d’économiser des ressources de thread, il s’agit toujours d’un gaspillage. Chaque thread tourne en boucle pendant le temps de réponse de la requête lorsqu’il peut être multitâche pour un autre point, ce qui vous permet de réduire le nombre de requêtes par seconde par thread.

Pour cette raison, et afin de vous montrer une insertion de classes POJO Java faisant un usage économe des threads, nous vous proposons à la place un exemple asynchrone d’insertion de document. Le support asynchrone du kit de développement logiciel (SDK) Java Azure Cosmos DB v4 est fourni par Project Reactor, une infrastructure d'application Java qui offre un modèle de programmation de dataflow déclaratif pour la programmation asynchrone basée sur l’événement. createDocumentsIfNotExist implémente la programmation asynchrone Project Reactor.

Dans createUserDocumentsIfNotExist, Flux.fromIterable(users) est une méthode de fabrique Project Reactor. Elle crée une instance Flux, source d’événements asynchrones. Dans ce cas, chaque « événement » asynchrone inclut un argument d’instance User. L’instance Flux contient deux événements de ce type, un pour maxaxam et un pour nelapin. Le code à l’intérieur de .flatMap( ... ).blockLast(); définit un pipeline d’opérations séquentielles à effectuer sur les événements émis par l’instance Flux.

L’une de ces opérations est createItem. L’idée est que ce pipeline est presque identique à l’implémentation synchrone, sauf que nous ne bloquons pas sur l’appel createItem. Plus précisément, l’appel vers blockLast() s’abonne au pipeline assemblé, ce qui amène le Flux à émettre de manière asynchrone ses deux événements. Le pipeline à l’intérieur de .flatMap( ... ).blockLast(); traite chacun de ces événements de manière pseudo-parallèle. Lorsqu’une requête est émise et qu’elle attend une réponse, Project Reactor traite d’autres requêtes en arrière-plan, ce qui est le facteur critique qui permet d’augmenter le taux de requêtes/seconde pour chaque thread.

Maintenant que nous avons expliqué des requêtes de base de données asynchrones efficaces avec Project Reactor, par souci de simplicité, le reste de ce labo utilisera des appels (synchronisés) de blocage. Pour plus d’informations sur Project Reactor, consultez le guide des modèles de réacteurs Azure Cosmos DB.

Lire des documents

  1. Pour lire des documents dans la base de données, ajoutez la méthode suivante à 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. Copiez et collez le code suivant à la fin de la méthode basicOperations, après le code de création du document :

    readUserDocument(maxaxam);
    
  3. Générez et exécutez CosmosApp.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

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

    Le terminal affiche la sortie suivante, où « Utilisateur lu 1 » indique que le document a été récupéré.

    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
    

    Vous pouvez également voir du texte supplémentaire émis par l’enregistreur d’événements.

Remplacer des documents

Azure Cosmos DB prend en charge le remplacement des documents JSON. En l’occurrence, nous allons mettre à jour un enregistrement utilisateur pour refléter une modification apportée à son nom.

  1. Ajoutez la méthode replaceUserDocument après la méthode readUserDocument dans le fichier 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. Copiez et collez le code suivant à la fin de la méthode basicOperations, après le code de lecture du document.

    maxaxam.setLastName("Suh");
    replaceUserDocument(maxaxam);
    
  3. Générez et exécutez CosmosApp.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

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

    Le terminal affiche la sortie suivante, où « Dernier nom remplacé par Suh » indique que le document a été remplacé.

    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
    

Supprimer des documents

  1. Copiez et collez la méthode deleteUserDocument sous votre méthode 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. Copiez et collez le code suivant à la fin de la méthode basicOperations.

    deleteUserDocument(maxaxam);
    
  3. Générez et exécutez CosmosApp.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

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

    Le terminal affiche la sortie suivante, où « Utilisateur supprimé 1 » indique que le document a été supprimé.

    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
    

Utiliser des documents par programme

Dans Azure Cosmos DB, les données sont stockées dans des documents JSON. Les documents peuvent être créés, récupérés, remplacés ou supprimés dans le portail ou programmatiquement. Ce labo se concentre sur les opérations de programmation. Toutes ces opérations sont disponibles dans le kit de développement logiciel (SDK) Azure Cosmos DB Java et sont également accessibles via le modèle de programmation Spring Data. Dans ce module, nous allons utiliser Spring Data Azure Cosmos DB pour effectuer des opérations CRUD (création, récupération, mise à jour et suppression) sur les données stockées NoSQL dans Azure Cosmos DB.

Les principales opérations pour des documents Spring Data Azure Cosmos DB représentent des opérations de base dans le modèle de programmation de données Spring Data :

  • save - pointer-écrire ou mettre à jour un document, selon que ce document existe déjà ou non.
  • view - pointer-lire un document
  • delete - pointer-supprimer un document

Pour effectuer une de ces opérations, vous aurez besoin de classes d’assistance (classes Java POJO) qui représentent les objets stocks dans la base de données. Étant donné que nous travaillons avec une base de données de clients en ligne, vous utiliserez la classe WebCustomer pour représenter les entités utilisateur. Cette classe stocke les données principales, telles que le prénom, le nom et l’ID utilisateur. (L’ID est obligatoire, car il s’agit de la clé de partition pour activer la mise à l’échelle horizontale.)

Chaque client web possède des préférences et des coupons d’expédition associés, vous souhaiterez donc que les types de données ShippingPreference et CouponsUsed représentent ces entités. Enfin, chaque client web peut avoir un historique des commandes qui ne lui est pas associé. Il est donc préférable d’avoir des entités OrderHistory séparées, avec une classe Java POJO correspondante.

Accédez à src/main/java/com/azure/cosmos/examples/springexamples. Vous verrez le POJO WebCustomer. Consultez maintenant le dossier common. Vous verrez plusieurs POJO : ShippingPreference, OrderHistory et CouponsUsed. Nous avons donc fourni toutes les classes POJO d’entités avec leurs classes d’assistance !

Ensuite, nous allons créer des entités et effectuer des opérations CRUD de base sur le conteneur Azure Cosmos DB et les documents qu’il contient. Vous pouvez transmettre à Azure Cosmos DB une instance ObjectNode qui spécifie directement le document JSON. Mais, Azure Cosmos DB peut également sérialiser des classes POJO Java en documents JSON. Il s’agit d’ailleurs de l’approche que nous recommandons car elle est la plus simple (les autres sont équivalentes).

Créer et mettre à jour des documents

  1. Ouvrez WebCustomer.java et examinez son contenu. Il doit se présenter comme suit :

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

    Notez que les méthodes d’accès aux champs id, userId et d’autres champs sont implicites (c’est-à-dire, non définies dans le code). Ce comportement est possible, car nous utilisons l’annotation@Data Project Lombok pour les créer automatiquement.

    L’annotation @NoArgsConstructor génère un constructeur sans argument qui définit les valeurs de champ par défaut. L’annotation @AllArgsConstructor génère un autre constructeur avec un ensemble complet d’arguments pour spécifier toutes les valeurs de champ directement.

    Notez que WebCustomer a une propriété id. Tous les documents Azure Cosmos DB nécessitent une propriété id. Il est donc nécessaire que toutes les classes POJO que nous avons l’intention de sérialiser en documents JSON aient un champ id.

  2. Ajoutez la méthode suivante à 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. Recherchez la méthode run, puis ajoutez le code suivant à la fin de cette méthode.

    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. Générez et exécutez CosmosSample.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

    mvn clean package
    mvn spring-boot:run
    

    Vous devez voir la sortie suivante dans le terminal :

    INFO: Creating WebCustomer 1
    INFO: Creating WebCustomer 2
    

Félicitations ! Vous avez créé et/ou mis à jour vos premières données dans Azure Cosmos DB à partir d’une application Java. Faisons une pause pour comprendre ce que vous venez de faire.

Dans run, il existe trois nouvelles actions :

  1. Créez/mettez à jour l’instance maxaxam WebCustomer.
  2. Créez/mettez à jour l’instance nelapin WebCustomer.
  3. Appelez createWebCustomerDocumentsIfNotExist, en passant par maxaxam et nelapin dans une liste.

L’appel de createWebCustomerDocumentsIfNotExist insère les deux instances WebCustomer en tant qu’éléments/documents dans Azure Cosmos DB. En vous faisant passer les instances WebCustomer sous la forme d’une liste, notre objectif est de modéliser une méthode performante pour la réception rapide de classes POJO dans Azure Cosmos DB, à l’aide de ressources de calcul minimales. createWebCustomerDocumentsIfNotExist implémente l’insertion asynchrone efficace d’une liste de classes POJO. Si l’un des documents existe déjà, save le mettra à jour au lieu de le créer.

Supposons que notre objectif soit de maximiser le nombre de requêtes par seconde dans chaque thread. En comparaison, l’approche de synchronisation appliquée à l’écriture de createWebCustomerDocumentsIfNotExist consiste à itérer au sein de chaque instance WebCustomer de webCustomers. Pour chaque WebCustomerwebCustomer, nous allons faire un appel de blocage pour save :

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

Ce style de synchronisation implémente un processus intuitif : envoyer la requête, attendre la réponse, envoyer la requête suivante. Toutefois, createWebCustomerDocumentsIfNotExist n’utilise pas cette approche, car les appels de blocage gaspillent les cycles du processeur pendant le temps de réponse de la requête, ce qui entraîne un faible taux de requêtes par seconde.

Vous pouvez contourner ce problème de requêtes par seconde en générant plusieurs threads afin d’effectuer des appels de requête de blocage parallèles. Les threads multiples entraînent une amélioration de la durée d’exécution. Toutefois, si votre objectif est d’économiser des ressources de thread, il s’agit toujours d’un gaspillage. Chaque thread tourne en boucle pendant le temps de réponse de la requête lorsqu’il peut être multitâche pour un autre point, ce qui vous permet de réduire le nombre de requêtes par seconde par thread.

Pour cette raison, et afin de vous montrer une insertion de classes POJO Java faisant un usage économe des threads, nous vous proposons à la place un exemple asynchrone d’insertion de document. Le support asynchrone de Spring Data est fourni par Project Reactor, une infrastructure d'application Java qui offre un modèle de programmation de dataflow déclaratif pour la programmation asynchrone basée sur l’événement. createWebCustomerDocumentsIfNotExist implémente la programmation asynchrone Project Reactor.

Dans createWebCustomerDocumentsIfNotExist, Flux.fromIterable(webCustomers) est une méthode de fabrique Project Reactor. Elle crée une instance Flux, source d’événements asynchrones. Dans ce cas, chaque « événement » asynchrone inclut un argument d’instance WebCustomer. L’instance Flux contient deux événements de ce type, un pour maxaxam et un pour nelapin. Le code à l’intérieur de .flatMap( ... ).blockLast(); définit un pipeline d’opérations séquentielles à effectuer sur les événements émis par l’instance Flux.

Dans ce cas, les deux opérations dans le pipeline sont des appels save. L’idée est que ce pipeline est presque identique à l’implémentation synchrone, sauf que nous ne bloquons pas sur l’appel save. Plus précisément, l’appel vers blockLast() s’abonne au pipeline assemblé, ce qui amène le Flux à émettre de manière asynchrone ses deux événements. Le pipeline à l’intérieur de .flatMap( ... ).blockLast(); traite chacun de ces événements de manière pseudo-parallèle. Lorsqu’une requête est émise et qu’elle attend une réponse, Project Reactor traite d’autres requêtes en arrière-plan, ce qui est le facteur critique qui permet d’augmenter le taux de requêtes/seconde pour chaque thread.

Maintenant que nous avons expliqué des requêtes de base de données asynchrones efficaces avec Project Reactor, par souci de simplicité, le reste de ce labo utilisera des appels asynchrones (des appels synchrones efficaces) de blocage. Pour plus d’informations sur Project Reactor, consultez le guide des modèles de réacteurs Azure Cosmos DB.

Lire des documents

  1. Pour lire des documents dans la base de données, ajoutez la méthode suivante à 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. Copiez et collez le code suivant à la fin de la méthode run, après le code de création du document :

    readWebCustomerDocument(maxaxam);
    
  3. Générez et exécutez CosmosSample.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

    mvn clean package
    mvn spring-boot:run
    

    Vous devez voir la sortie suivante dans le terminal. « Read user 1 » indique que le document a été récupéré.

    INFO: Read webCustomer 1
    

Supprimer des documents

  1. Copiez et collez la méthode deleteWebCustomerDocument sous votre méthode 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. Copiez et collez le code suivant à la fin de la méthode run.

    deleteWebCustomerDocument(maxaxam);
    
  3. Générez et exécutez CosmosSample.java dans l’IDE ou exécutez le programme sur le terminal à l’aide de :

    mvn clean package
    mvn spring-boot:run
    

    Vous devez voir la sortie suivante dans le terminal. « Deleted user 1 » indique que le document a été supprimé.

    INFO: Deleted webCustomer 1
    

Dans cette unité, vous avez créé, mis à jour, lu et supprimé des documents dans votre base de données Azure Cosmos DB.