Esercizio - Creare, leggere, aggiornare ed eliminare dati NoSQL a livello di codice

Completato

È stata effettuata la connessione a Azure Cosmos DB. In questa unità verranno creati documenti degli utenti nella raccolta WebCustomers e verranno poi recuperati in base all'ID, sostituiti ed eliminati.

Uso dei documenti a livello di codice

I dati vengono archiviati in documenti JSON in Azure Cosmos DB. I documenti possono essere creati, recuperati, sostituiti o eliminati nel portale oppure a livello di codice. Questo lab è incentrato sulle operazioni a livello di codice. Azure Cosmos DB offre SDK lato client per .NET, .NET Core, Java, Node.js e Python, ognuno dei quali supporta queste operazioni. In questo modulo si userà Java SDK per eseguire operazioni CRUD (Create, Retrieve, Update, Delete) sui dati NoSQL archiviati in Azure Cosmos DB.

Le operazioni principali per i documenti di Azure Cosmos DB fanno parte della classe CosmosAsyncContainer:

Upsert esegue un'operazione di creazione o sostituzione a seconda dell'esistenza o meno del documento.

Per eseguire queste operazioni, sono necessarie classi helper (classi POJO Java) che rappresentano gli oggetti archiviati nel database. Poiché si sta lavorando con un database di utenti, sarà necessaria una classe User che rappresenta le entità utente. Questa classe memorizzerà i dati primari, ad esempio il nome, il cognome e l'ID utente. (L'ID è obbligatorio perché è la chiave di partizione per abilitare la scalabilità orizzontale).

Ogni utente dispone di alcune preferenze e buoni di spedizione associati, pertanto saranno necessari tipi di oggetto ShippingPreference e CouponsUsed per rappresentare tali entità. Infine, ogni utente può disporre di una cronologia degli ordini potenzialmente senza vincoli, quindi saranno necessarie entità OrderHistory separate con una classe POJO Java corrispondente.

Passare a src/main/java/com/azure/azure-cosmos-java-sql-app-mslearn es esaminare la cartella datatypes. Verranno visualizzati diversi POJO: User, ShippingPreference, OrderHistory e CouponsUsed. Sono quindi stati forniti tutti gli oggetti POJO delle entità e le relative classi helper.

Si creeranno quindi alcune entità e si eseguiranno alcune operazioni CRUD di base sul contenitore di Azure Cosmos DB e sui documenti in esso presenti. È possibile passare ad Azure Cosmos DB un'istanza di Jackson ObjectNode che specifica direttamente il documento JSON, ma Azure Cosmos DB è anche in grado di serializzare gli oggetti POJO Java in JSON e questo approccio è consigliato in quanto è l'opzione più semplice.

Creare i documenti

  1. Aprire User.java ed esaminarne il contenuto. L'output dovrebbe essere simile al seguente:

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

    Osservare che i metodi di accesso per i campi id, userId e così via sono impliciti (non definiti nel codice). Questo comportamento è possibile perché si usa l'annotazione @Data di Project Lombok per la creazione automatica.

    L'annotazione @NoArgsConstructor genererà un costruttore senza argomenti che imposta i valori di campo predefiniti. L'annotazione @AllArgsConstructor genererà un altro costruttore con un set completo di argomenti per specificare direttamente tutti i valori di campo.

    Si noti che User ha una proprietà id. Tutti i documenti di Azure Cosmos DB richiedono una proprietà id, pertanto tutti gli oggetti POJO che si prevede di serializzare nei documenti JSON devono avere un campo id.

  2. Aggiungere il metodo seguente 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. Tornare al metodo basicOperations e aggiungere il codice seguente alla fine del metodo prima della chiamata di 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. Compilare ed eseguire CosmosApp.java nell'IDE oppure eseguire il programma nel terminale usando:

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

    Il terminale visualizzerà l'output man mano che l'applicazione crea ogni nuovo documento utente.

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

    È possibile che venga visualizzato anche testo aggiuntivo emesso dal logger, come timestamp.

Complimenti. Sono stati creati i primi dati in Azure Cosmos DB da un'applicazione Java. Fermarsi a esaminare ciò che è stato fatto.

In basicOperations sono disponibili tre nuove azioni:

  1. Creare l'istanza maxaxam User.
  2. Creare l'istanza nelapin User.
  3. Chiamare createUserDocumentsIfNotExist, passando maxaxam e nelapin in un elenco.

Chiamando createUserDocumentsIfNotExist vengono inserite entrambe le istanze di User come elementi/documenti in Azure Cosmos DB. Quando si passano le istanze di User in un elenco, la finalità è quella di modellare un metodo efficiente per l'inserimento rapido di oggetti POJO in Azure Cosmos DB, usando risorse di calcolo minime. createUserDocumentsIfNotExist implementa un inserimento asincrono efficiente di un elenco di oggetti POJO.

Si supponga che l'obiettivo sia quello di ottimizzare le richieste al secondo per ogni thread. Come confronto, l'approccio sincrono alla scrittura di createUserDocumentsIfNotExist, ignorando per un attimo il controllo readItem, consisterebbe nello scorrere ogni istanza User in users. Per ogni oggetto User u, effettuare una chiamata di blocco a createItem:

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

Questo stile sincrono implementa un processo intuitivo: invio di una richiesta, attesa della risposta, invio della richiesta successiva. Tuttavia, createUserDocumentsIfNotExist non usa questo approccio perché le chiamate di blocco essenzialmente sprecano i cicli della CPU durante il tempo di risposta alla richiesta, causando un basso numero di richieste al secondo.

È possibile aggirare questo problema di richieste al secondo generando più thread per effettuare chiamate di richiesta di blocco parallele. I thread multipli produrranno un miglioramento del tempo di esecuzione. Tuttavia, se l'obiettivo è non sprecare le risorse di thread, questo risultato è ancora inutile. Ogni thread viene riprodotto a ciclo continuo durante il tempo di risposta della richiesta quando potrebbe invece essere multitasking in un altro modo, fornendo richieste insufficienti al secondo per ogni thread.

Per questo motivo, e allo scopo di illustrare l'inserimento di oggetti POJO Java con un uso dei thread efficiente, è stato invece fornito un esempio asincrono di inserimento di documenti. Il supporto asincrono della versione 4 di Java SDK per Azure Cosmos DB deriva da Project Reactor, un framework di applicazione Java che fornisce un modello di programmazione di flusso di dati dichiarativo basato sul flusso per la programmazione asincrona guidata dagli eventi. createDocumentsIfNotExist implementa la programmazione asincrona di Project Reactor.

In createUserDocumentsIfNotExist, Flux.fromIterable(users) è un metodo factory del reattore del progetto. Crea un'istanza di Flux che è un'origine di eventi asincroni. In questo caso, ogni "evento" asincrono include un argomento dell'istanza User. L'istanza di Flux contiene due eventi di questo tipo, uno per maxaxam e uno per nelapin. Il codice all'interno di .flatMap( ... ).blockLast(); definisce una pipeline di operazioni sequenziali da eseguire sugli eventi generati dall'istanza di Flux.

Una di queste operazioni è createItem. Il concetto è che questa pipeline è quasi identica all'implementazione sincrona, ad eccezione del fatto che non si blocca la chiamata createItem. In particolare, la chiamata a blockLast() sottoscrive alla pipeline assemblata, facendo in modo che Flux emetta in modo asincrono i due eventi. La pipeline all'interno di .flatMap( ... ).blockLast(); elabora ognuno di questi eventi in modo pseudo-parallelo. Quando una richiesta viene inviata ed è in attesa di una risposta, Project Reactor elabora le altre richieste in background e questo è il fattore critico per ottimizzare le richieste al secondo per ogni thread.

Ora che sono state illustrate le richieste di database asincrone efficienti con Project Reactor, per semplicità nel resto di questo lab verranno usate le chiamate di blocco (sincrone). Per altre informazioni su Project Reactor, vedere la guida del modello Reactor di Azure Cosmos DB.

Leggere i documenti

  1. Per leggere i documenti dal database, aggiungere il metodo seguente 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. Copiare e incollare il codice seguente alla fine del metodo basicOperations, dopo il codice di creazione del documento:

    readUserDocument(maxaxam);
    
  3. Compilare ed eseguire CosmosApp.java nell'IDE oppure eseguire il programma nel terminale usando:

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

    Il terminale visualizza l'output seguente, in cui "Read user 1" indica che il documento è stato recuperato.

    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
    

    È possibile che venga visualizzato anche testo aggiuntivo emesso dal logger.

Sostituire i documenti

Azure Cosmos DB supporta la sostituzione di documenti JSON. In questo caso, verrà aggiornato un record utente per registrare una modifica al cognome.

  1. Aggiungere il metodo replaceUserDocument dopo il metodo readUserDocument nel file 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. Copiare e incollare il codice seguente alla fine del metodo basicOperations, dopo il codice di lettura del documento.

    maxaxam.setLastName("Suh");
    replaceUserDocument(maxaxam);
    
  3. Compilare ed eseguire CosmosApp.java nell'IDE oppure eseguire il programma nel terminale usando:

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

    Il terminale visualizza l'output seguente, in cui "Replaced last name for Suh" indica che il documento è stato sostituito.

    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
    

Eliminare documenti.

  1. Copiare e incollare il metodo deleteUserDocument nel metodo 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. Copiare e incollare il codice seguente alla fine del metodo basicOperations.

    deleteUserDocument(maxaxam);
    
  3. Compilare ed eseguire CosmosApp.java nell'IDE oppure eseguire il programma nel terminale usando:

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

    Il terminale visualizza l'output seguente, in cui "Deleted user 1" indica che il documento è stato eliminato.

    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
    

Uso dei documenti a livello di codice

I dati vengono archiviati in documenti JSON in Azure Cosmos DB. I documenti possono essere creati, recuperati, sostituiti o eliminati nel portale oppure a livello di codice. Questo lab è incentrato sulle operazioni a livello di codice. Tutte queste operazioni sono disponibili in Azure Cosmos DB SDK Java e sono accessibili anche tramite il modello di programmazione Spring Data. In questo modulo si userà Spring Data per Azure Cosmos DB per eseguire operazioni CRUD (Create, Retrieve, Update, Delete) sui dati NoSQL archiviati in Azure Cosmos DB.

Le operazioni principali per i documenti di Spring Data per Azure Cosmos DB sono operazioni di base nel modello di programmazione Spring Data:

  • save: scrivere o aggiornare un documento, a seconda della presenza o meno del documento.
  • view: leggere un documento
  • delete: eliminare un documento

Per eseguire queste operazioni, sono necessarie classi helper (classi POJO Java) che rappresentano gli oggetti archiviati nel database. Poiché si sta lavorando con un database di clienti online, si vorrà usare la classe WebCustomer per rappresentare le entità utente. Questa classe memorizzerà i dati primari, ad esempio il nome, il cognome e l'ID utente. (L'ID è obbligatorio perché è la chiave di partizione per abilitare la scalabilità orizzontale).

Poiché ogni cliente Web ha alcune preferenze e buoni di spedizione associati, si vorranno usare i tipi di dati ShippingPreference e CouponsUsed per rappresentare queste entità. Infine, ogni cliente Web può avere una cronologia degli ordini potenzialmente senza vincoli, quindi saranno necessarie entità OrderHistory separate con una classe POJO Java corrispondente.

Passare a src/main/java/com/azure/cosmos/examples/springexamples. Viene visualizzato l'oggetto POJO WebCustomer. Esaminare ora la cartella common. Vengono visualizzati diversi oggetti POJO: ShippingPreference, OrderHistory e CouponsUsed. Sono quindi stati forniti tutti gli oggetti POJO delle entità e le relative classi helper.

Si creeranno quindi alcune entità e si eseguiranno alcune operazioni CRUD di base sul contenitore di Azure Cosmos DB e sui documenti in esso presenti. È possibile passare ad Azure Cosmos DB un'istanza di Jackson ObjectNode che specifica direttamente il documento JSON, ma Azure Cosmos DB è anche in grado di serializzare gli oggetti POJO Java in JSON e questo approccio è consigliato in quanto è l'opzione più semplice.

Creare e aggiornare i documenti

  1. Aprire WebCustomer.java ed esaminarne il contenuto. L'output dovrebbe essere simile al seguente:

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

    Osservare che i metodi di accesso per i campi id, userId e così via sono impliciti (non definiti nel codice). Questo comportamento è possibile perché si usa l'annotazione @Data di Project Lombok per la creazione automatica.

    L'annotazione @NoArgsConstructor genererà un costruttore senza argomenti che imposta i valori di campo predefiniti. L'annotazione @AllArgsConstructor genererà un altro costruttore con un set completo di argomenti per specificare direttamente tutti i valori di campo.

    Si noti che WebCustomer ha una proprietà id. Tutti i documenti di Azure Cosmos DB richiedono una proprietà id, pertanto tutti gli oggetti POJO che si prevede di serializzare nei documenti JSON devono avere un campo id.

  2. Aggiungere il metodo seguente 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. Trovare il metodo run e aggiungere il codice seguente alla fine del metodo.

    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. Compilare ed eseguire CosmosSample.java nell'IDE oppure eseguire il programma nel terminale usando:

    mvn clean package
    mvn spring-boot:run
    

    Nell'output del terminale verrà visualizzato

    INFO: Creating WebCustomer 1
    INFO: Creating WebCustomer 2
    

Complimenti. Sono stati creati e/o aggiornati i primi dati in Azure Cosmos DB da un'applicazione Java. Fermarsi a esaminare ciò che è stato fatto.

In run sono disponibili tre nuove azioni:

  1. Creare/aggiornare l'istanza maxaxam WebCustomer.
  2. Creare/aggiornare l'istanza nelapin WebCustomer.
  3. Chiamare createWebCustomerDocumentsIfNotExist, passando maxaxam e nelapin in un elenco.

Chiamando createWebCustomerDocumentsIfNotExist vengono inserite entrambe le istanze di WebCustomer come elementi/documenti in Azure Cosmos DB. Quando si passano le istanze di WebCustomer in un elenco, la finalità è quella di modellare un metodo efficiente per l'inserimento rapido di oggetti POJO in Azure Cosmos DB, usando risorse di calcolo minime. createWebCustomerDocumentsIfNotExist implementa un inserimento asincrono efficiente di un elenco di oggetti POJO. Se uno dei documenti esiste già, save eseguirà un aggiornamento invece di creare un documento.

Si supponga che l'obiettivo sia quello di ottimizzare le richieste al secondo per ogni thread. Come confronto, l'approccio sincrono alla scrittura di createWebCustomerDocumentsIfNotExistconsisterebbe nell'eseguire l'iterazione in ogni istanza di WebCustomer in webCustomers. Per ogni oggetto WebCustomer webCustomer, effettuare una chiamata di blocco a save:

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

Questo stile sincrono implementa un processo intuitivo: invio di una richiesta, attesa della risposta, invio della richiesta successiva. Tuttavia, createWebCustomerDocumentsIfNotExist non usa questo approccio perché le chiamate di blocco essenzialmente sprecano i cicli della CPU durante il tempo di risposta alla richiesta, causando un basso numero di richieste al secondo.

È possibile aggirare questo problema di richieste al secondo generando più thread per effettuare chiamate di richiesta di blocco parallele. I thread multipli produrranno un miglioramento del tempo di esecuzione. Tuttavia, se l'obiettivo è non sprecare le risorse di thread, questo risultato è ancora inutile. Ogni thread viene riprodotto a ciclo continuo durante il tempo di risposta della richiesta quando potrebbe invece essere multitasking in un altro modo, fornendo richieste insufficienti al secondo per ogni thread.

Per questo motivo, e allo scopo di illustrare l'inserimento di oggetti POJO Java con un uso dei thread efficiente, è stato invece fornito un esempio asincrono di inserimento di documenti. Il supporto asincrono di Spring Data deriva da Project Reactor, un framework di applicazione Java che fornisce un modello di programmazione di flusso di dati dichiarativo basato sul flusso per la programmazione asincrona guidata dagli eventi. createWebCustomerDocumentsIfNotExist implementa la programmazione asincrona di Project Reactor.

In createWebCustomerDocumentsIfNotExist, Flux.fromIterable(webCustomers) è un metodo factory del reattore del progetto. Crea un'istanza di Flux che è un'origine di eventi asincroni. In questo caso, ogni "evento" asincrono include un argomento dell'istanza WebCustomer. L'istanza di Flux contiene due eventi di questo tipo, uno per maxaxam e uno per nelapin. Il codice all'interno di .flatMap( ... ).blockLast(); definisce una pipeline di operazioni sequenziali da eseguire sugli eventi generati dall'istanza di Flux.

In questo caso le due operazioni della pipeline sono chiamate save. Il concetto è che questa pipeline è quasi identica all'implementazione sincrona, ad eccezione del fatto che non si blocca la chiamata save. In particolare, la chiamata a blockLast() sottoscrive alla pipeline assemblata, facendo in modo che Flux emetta in modo asincrono i due eventi. La pipeline all'interno di .flatMap( ... ).blockLast(); elabora ognuno di questi eventi in modo pseudo-parallelo. Quando una richiesta viene inviata ed è in attesa di una risposta, Project Reactor elabora le altre richieste in background e questo è il fattore critico per ottimizzare le richieste al secondo per ogni thread.

Ora che sono state illustrate le richieste di database asincrone efficienti con Project Reactor, per semplicità nel resto di questo lab verranno usate le chiamate asincrone di blocco (di fatto chiamate sincrone). Per altre informazioni su Project Reactor, vedere la guida del modello Reactor di Azure Cosmos DB.

Leggere i documenti

  1. Per leggere i documenti dal database, aggiungere il metodo seguente 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. Copiare e incollare il codice seguente alla fine del metodo run, dopo il codice di creazione del documento:

    readWebCustomerDocument(maxaxam);
    
  3. Compilare ed eseguire CosmosSample.java nell'IDE oppure eseguire il programma nel terminale usando:

    mvn clean package
    mvn spring-boot:run
    

    Nell'output del terminale verrà visualizzato quanto segue. "Read User 1" indica che il documento è stato recuperato.

    INFO: Read webCustomer 1
    

Eliminare documenti.

  1. Copiare e incollare il metodo deleteWebCustomerDocument nel metodo 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. Copiare e incollare il codice seguente alla fine del metodo run.

    deleteWebCustomerDocument(maxaxam);
    
  3. Compilare ed eseguire CosmosSample.java nell'IDE oppure eseguire il programma nel terminale usando:

    mvn clean package
    mvn spring-boot:run
    

    Nell'output del terminale verrà visualizzato quanto segue. "Deleted user 1" indica che il documento è stato eliminato.

    INFO: Deleted webCustomer 1
    

In questa unità sono stati creati, aggiornati, letti ed eliminati documenti nel database di Azure Cosmos DB.