Ćwiczenie — programowe tworzenie, odczytywanie, aktualizowanie i usuwanie danych NoSQL
Połączenie z usługą Azure Cosmos DB zostało nawiązane. W tej lekcji utworzysz dokumenty użytkowników w kolekcji WebCustomers
. Następnie pobierzesz je według identyfikatora, zastąpisz i usuniesz.
Programistyczna praca z dokumentami
Dane są przechowywane w dokumentach JSON w usłudze Azure Cosmos DB. Dokumenty mogą być tworzone, pobierane, zastępowane lub usuwane w portalu lub programowo. To laboratorium koncentruje się na operacjach programowych. Usługa Azure Cosmos DB udostępnia zestawy SDK po stronie klienta dla oprogramowania .NET, .NET Core, Java, Node.js i Python, z których każdy obsługuje te operacje. W tym module będziemy używać zestawu SDK Java do wykonywania operacji CRUD (tworzenie, pobieranie, aktualizowanie i usuwanie) na danych NoSQL przechowywanych w usłudze Azure Cosmos DB.
Główne operacje dla dokumentów usługi Azure Cosmos DB to część klasy CosmosAsyncContainer:
Operacja upsert wykonuje operację tworzenia lub zastępowania w zależności od tego, czy dokument już istnieje.
Aby wykonać dowolną z tych operacji, potrzebne będą klasy pomocy (klasy POJO języka Java) reprezentujące obiekty przechowywane w bazie danych. Ponieważ pracujemy z bazą danych użytkowników, warto mieć klasę User
reprezentującą jednostki użytkowników. Będzie ona przechowywać podstawowe dane, takie jak imię, nazwisko i identyfikator użytkownika. (Identyfikator jest potrzebny, ponieważ jest kluczem partycji umożliwiającym skalowanie w poziomie).
Każdy użytkownik ma przypisane preferencje dostawy i kupony rabatowe, więc potrzebne będą typy danych ShippingPreference
i CouponsUsed
reprezentujące te jednostki. Każdy użytkownik może również mieć potencjalnie nieograniczoną historię zamówień, więc potrzebne będą oddzielne jednostki OrderHistory
z odpowiadającą klasą POJO języka Java.
Przejdź do ścieżki src/main/java/com/azure/azure-cosmos-java-sql-app-mslearn i otwórz folder datatypes. Znajdziesz w nim kilka klas POJO:User
, ShippingPreference
, OrderHistory
oraz CouponsUsed
. Udostępniliśmy Ci wszystkie potrzebne klasy POJO jednostek i ich klasy pomocy.
Następnie utworzymy parę jednostek i wykonamy kilka podstawowych operacji CRUD na kontenerze usługi Azure Cosmos DB i dokumentach, które zawiera. Usłudze Azure Cosmos DB możesz przekazać wystąpienie ObjectNode
biblioteki Jackson, która bezpośrednio określa dokument JSON. Jednak usługa Azure Cosmos DB umożliwia również serializację klas POJO języka Java do formatu JSON i zalecamy takie podejście jako najprostszą opcję (o ile pozostałe parametry są takie same).
Tworzenie dokumentów
Otwórz plik User.java i przejrzyj jego zawartość. Powinna to wyglądać następująco:
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; }
Zwróć uwagę, że metody dostępu dla pól
id
,userId
i innych są niejawne (niezdefiniowane w kodzie). Takie zachowanie jest możliwe, ponieważ używamy adnotacji@Data
biblioteki Project Lombok w celu ich automatycznego tworzenia.Adnotacja
@NoArgsConstructor
wygeneruje konstruktor bez argumentów, który ustawia domyślne wartości pól. Adnotacja@AllArgsConstructor
wygeneruje kolejny konstruktor z pełnym zestawem argumentów, który bezpośrednio określi wartości wszystkich pól.Zauważ, że klasa
User
ma właściwośćid
. Wszystkie dokumenty usługi Azure Cosmos DB wymagają właściwościid
, dlatego wszystkie klasy POJO, które zamierzamy serializować do dokumentów JSON, muszą mieć poleid
.Dodaj następującą metodę do pliku 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(); }
Następnie wróć do metody
basicOperations
i dodaj następujący element na końcu tej metody przed wywołaniem metodyclient.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)));
Skompiluj i uruchom plik CosmosApp.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
W miarę tego, jak aplikacja będzie tworzyć poszczególne nowe dokumenty użytkowników, w terminalu będą wyświetlane dane wyjściowe.
INFO: Database and container validation complete INFO: Creating User 1 INFO: Creating User 2
Rejestrator może wyświetlić dodatkowy tekst, na przykład znaczniki czasu.
Gratulacje! Udało Ci się utworzyć pierwsze dane w usłudze Azure Cosmos DB z aplikacji języka Java. Zatrzymajmy się i oceńmy, co zostało zrobione.
W metodzie basicOperations
są trzy nowe akcje:
- Utworzenie wystąpienia maxaxam klasy
User
. - Utworzenie wystąpienia nelapin klasy
User
. - Wywołanie metody
createUserDocumentsIfNotExist
z przekazaniem listy wystąpień maxaxam oraz nelapin.
Wywołanie metody createUserDocumentsIfNotExist
powoduje wstawienie obu wystąpień klasy User
jako elementów/dokumentów w usłudze Azure Cosmos DB. W przypadku przekazania wystąpień klasy User
jako listy, naszym zamiarem jest modelowanie wydajnej metody do szybkiego pozyskiwania klas POJO w usłudze Azure Cosmos DB przy użyciu minimalnych zasobów obliczeniowych. Metoda createUserDocumentsIfNotExist
implementuje wydajne asynchroniczne wstawianie listy klas POJO.
Załóżmy, że naszym celem jest maksymalizacja liczby żądań na sekundę na wątek. Dla porównania podejście synchroniczne do zapisu metody createUserDocumentsIfNotExist
— ignorując przez chwilę kontrolę operacji readItem
— polegałoby na wykonaniu iteracji dla każdego wystąpienia klasy User
na liście users
. Dla każdego wystąpienia klasy User
u
należałoby wykonać wywołanie blokujące operacji createItem
:
container.createItem(u, new PartitionKey(u.getUserId()), new CosmosItemRequestOptions()).block(); // <= Note the .block() which loops until request response.
Ten styl synchroniczny implementuje intuicyjny proces — wysłanie żądania, poczekanie na odpowiedź, wysłanie następnego żądania itd. Metoda createUserDocumentsIfNotExist
nie stosuje jednak tego podejścia, ponieważ blokowanie wywołań będzie zasadniczo utratą cykli procesora CPU w trakcie czasu odpowiedzi na żądanie, co spowoduje niską liczbę żądań na sekundę.
Aby uniknąć tego problemu związanego z niską liczbą żądań na sekundę, możesz zduplikować kilka wątków, by umożliwić wykonywanie równoległych wywoływań żądań blokowania. Zduplikowane wątki skrócą czas wykonywania żądania. Jednak jeśli chcesz zaoszczędzić zasoby wątków, takie rozwiązanie również będzie nieekonomiczne. Każdy wątek wykonuję pętlę w trakcie czasu odpowiedzi na żądanie, gdy zamiast tego mógłby wykonywać wiele innych zadań jednocześnie, dając niską ilość żądań na sekundę na wątek.
Z tego powodu, oraz w celu pokazania wydajnego wątkowo wstawiania klas POJO języka Java, udostępniliśmy asynchroniczny przykład wstawiania dokumentu. Obsługa asynchroniczna zestawu Java SDK 4 usługi Azure Cosmos DB pochodzi z Project Reactor, struktury aplikacji języka Java, która zapewnia oparty na strumieniu model programowania deklaratywnego przepływu danych umożliwiający programowanie oparte na zdarzeniach asynchronicznych. Metoda createDocumentsIfNotExist
implementuje programowanie asynchroniczne biblioteki Project Reactor.
W metodzie createUserDocumentsIfNotExist
Flux.fromIterable(users)
jest metodą tworzącą biblioteki Project Reactor. Tworzy wystąpienie klasy Flux
, które jest źródłem zdarzeń asynchronicznych. W tym przypadku każde „zdarzenie” asynchroniczne zawiera argument wystąpienia klasy User
. Wystąpienie klasy Flux
zawiera dwa takie zdarzenia — jedno dla wystąpienia maxaxam i jedno dla wystąpienia nelapin. Kod metody .flatMap( ... ).blockLast();
definiuje potok operacji sekwencyjnych, które należy wykonać na zdarzeniach emitowanych przez wystąpienie klasy Flux
.
Jedną z tych operacji jest createItem
. Ten potok jest niemal identyczny do modelu synchronicznego, z tą różnicą, że nie wywołanie operacji createItem
nie jest blokujące. Wywołanie metody blockLast()
powoduje subskrypcję przygotowanego potoku, przez co wystąpienie Flux
asynchronicznie emituje oba swoje zdarzenia. Następnie potok wewnątrz elementu .flatMap( ... ).blockLast();
przetwarza każde z tych zdarzeń w sposób pseudo-równoległy. Gdy jedno żądanie jest wystawiane i czeka na odpowiedź, biblioteka Project Reactor będzie przetwarzać inne żądania w tle, co jest krytycznym czynnikiem w maksymalizacji liczby żądań na sekundę na wątek.
Skoro poznaliśmy już wydajne asynchroniczne żądania bazy danych za pomocą biblioteki Project Reactor, dla uproszczenia w pozostałej części tego laboratorium będziemy używać wywołań blokujących (synchronicznych). Aby dowiedzieć się więcej na temat biblioteki Project Reactor, zobacz Przewodnik po wzorcu biblioteki Reactor usługi Azure Cosmos DB.
Czytanie dokumentów
W celu odczytu dokumentów z bazy danych, dodaj następującą metodę do klasy
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; }
Skopiuj i wklej następujący kod na końcu metody
basicOperations
po kodzie tworzenia dokumentu:readUserDocument(maxaxam);
Skompiluj i uruchom plik CosmosApp.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
Terminal wyświetli następujący komunikat, przy czym tekst „Read user 1” („Odczyt — użytkownik 1”) wskazuje, że dokument został pobrany.
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
Rejestrator może też wyświetlić dodatkowy tekst.
Zastępowanie dokumentów
Usługa Azure Cosmos DB obsługuje zastępowanie dokumentów JSON. W tym przypadku zaktualizujemy rekord użytkownika, aby uwzględnić zmianę jego nazwiska.
Dodaj metodę
replaceUserDocument
po metodziereadUserDocument
w pliku 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()); } }
Skopiuj i wklej następujący kod na końcu
basicOperations
metody po przeczytaniu kodu dokumentu.maxaxam.setLastName("Suh"); replaceUserDocument(maxaxam);
Skompiluj i uruchom plik CosmosApp.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
Terminal wyświetli następujący komunikat, przy czym tekst „Replaced last name for Suh” („Zmieniono nazwisko użytkownika Suh”) wskazuje, że dokument został zastąpiony.
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
Usuwanie dokumentów
Skopiuj i wklej metodę
deleteUserDocument
pod metodą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()); } }
Skopiuj i wklej następujący kod na końcu metody
basicOperations
.deleteUserDocument(maxaxam);
Skompiluj i uruchom plik CosmosApp.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn exec:java -Dexec.mainClass="com.azure.cosmos.examples.mslearnbasicapp.CosmosApp"
Terminal wyświetli następujący komunikat, przy czym tekst „Deleted user 1” („Usunięto — użytkownik 1”) wskazuje, że dokument został usunięty.
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
Programistyczna praca z dokumentami
Dane są przechowywane w dokumentach JSON w usłudze Azure Cosmos DB. Dokumenty mogą być tworzone, pobierane, zastępowane lub usuwane w portalu lub programowo. To laboratorium koncentruje się na operacjach programowych. Wszystkie te operacje są dostępne w zestawie JAVA SDK usługi Azure Cosmos DB i są również dostępne za pośrednictwem modelu programowania Spring Data. W tym module będziemy używać projektu Spring Data w usłudze Azure Cosmos DB do wykonywania operacji CRUD (tworzenie, pobieranie, aktualizowanie i usuwanie) na danych NoSQL przechowywanych w usłudze Azure Cosmos DB.
Główne operacje dotyczące dokumentów projektu Spring Data w usłudze Azure Cosmos DB to podstawowe operacje w modelu programowania Spring Data:
save
— pisanie lub aktualizowanie dokumentu, w zależności od tego, czy dokument już istnieje.view
— odczytywanie dokumentudelete
— usuwanie dokumentu
Aby wykonać dowolną z tych operacji, potrzebne będą klasy pomocy (klasy POJO języka Java) reprezentujące obiekty przechowywane w bazie danych. Ponieważ pracujemy z bazą danych klientów online, warto użyć klasy WebCustomer
do reprezentowania jednostek użytkowników. Będzie ona przechowywać podstawowe dane, takie jak imię, nazwisko i identyfikator użytkownika. (Identyfikator jest potrzebny, ponieważ jest kluczem partycji umożliwiającym skalowanie w poziomie).
Każdy użytkownik w Internecie ma przypisane preferencje dostawy i kupony rabatowe, więc potrzebne będą typy danych ShippingPreference
i CouponsUsed
reprezentujące te jednostki. Każdy użytkownik w Internecie może również mieć potencjalnie nieograniczoną historię zamówień, więc potrzebne będą oddzielne jednostki OrderHistory
z odpowiadającą klasą POJO języka Java.
Przejdź do folderu src/main/java/com/azure/cosmos/examples/springexamples. Zobaczysz klasę POJO WebCustomer
. Teraz przejdź do folderu common. Znajdziesz w nim kilka klas POJO: ShippingPreference
, OrderHistory
i CouponsUsed
. Udostępniliśmy Ci wszystkie potrzebne klasy POJO jednostek i ich klasy pomocy.
Następnie utworzymy parę jednostek i wykonamy kilka podstawowych operacji CRUD na kontenerze usługi Azure Cosmos DB i dokumentach, które zawiera. Usłudze Azure Cosmos DB możesz przekazać wystąpienie ObjectNode
biblioteki Jackson, która bezpośrednio określa dokument JSON. Jednak usługa Azure Cosmos DB umożliwia również serializację klas POJO języka Java do formatu JSON i zalecamy takie podejście jako najprostszą opcję (o ile pozostałe parametry są takie same).
Tworzenie i aktualizowanie dokumentów
Otwórz plik WebCustomer.java i przejrzyj jego zawartość. Powinna to wyglądać następująco:
// 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; }
Zwróć uwagę, że metody dostępu dla pól
id
,userId
i innych są niejawne (niezdefiniowane w kodzie). Takie zachowanie jest możliwe, ponieważ używamy adnotacji@Data
biblioteki Project Lombok w celu ich automatycznego tworzenia.Adnotacja
@NoArgsConstructor
wygeneruje konstruktor bez argumentów, który ustawia domyślne wartości pól. Adnotacja@AllArgsConstructor
wygeneruje kolejny konstruktor z pełnym zestawem argumentów, który bezpośrednio określi wartości wszystkich pól.Zauważ, że klasa
WebCustomer
ma właściwośćid
. Wszystkie dokumenty usługi Azure Cosmos DB wymagają właściwościid
, dlatego wszystkie klasy POJO, które zamierzamy serializować do dokumentów JSON, muszą mieć poleid
.Dodaj następującą metodę do pliku 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(); }
Wróć do metody
run
i dodaj następujący kod na końcu tej metody.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)));
Skompiluj i uruchom plik CosmosSample.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn spring-boot:run
Oprócz danych wyjściowych terminalu powinny zostać wyświetlone następujące dane
INFO: Creating WebCustomer 1 INFO: Creating WebCustomer 2
Gratulacje! Udało Ci się utworzyć i/lub zaktualizować pierwsze dane w usłudze Azure Cosmos DB na podstawie aplikacji języka Java. Zatrzymajmy się i oceńmy, co zostało zrobione.
W metodzie run
są trzy nowe akcje:
- Utworzenie/zaktualizowanie wystąpienia maxaxam klasy
WebCustomer
. - Utworzenie/zaktualizowanie wystąpienia nelapin klasy
WebCustomer
. - Wywołanie metody
createWebCustomerDocumentsIfNotExist
z przekazaniem listy wystąpień maxaxam oraz nelapin.
Wywołanie metody createWebCustomerDocumentsIfNotExist
powoduje wstawienie obu wystąpień klasy WebCustomer
jako elementów/dokumentów w usłudze Azure Cosmos DB. W przypadku przekazania wystąpień klasy WebCustomer
jako listy, naszym zamiarem jest modelowanie wydajnej metody do szybkiego pozyskiwania klas POJO w usłudze Azure Cosmos DB przy użyciu minimalnych zasobów obliczeniowych. Metoda createWebCustomerDocumentsIfNotExist
implementuje wydajne asynchroniczne wstawianie listy klas POJO. Jeśli dowolny dokument już istnieje, element save
wykona aktualizację zamiast tworzenia dokumentu.
Załóżmy, że naszym celem jest maksymalizacja liczby żądań na sekundę na wątek. Dla porównania podejście synchroniczne do zapisu metody createWebCustomerDocumentsIfNotExist
polegałoby na wykonaniu iteracji dla każdego wystąpienia klasy WebCustomer
w elemencie webCustomers
. Dla każdego wystąpienia klasy WebCustomer
webCustomer
należałoby wykonać wywołanie blokujące operacji save
:
this.reactiveWebCustomerRepository.save(webCustomer).block(); // <= Note the .block() which loops until request response.
Ten styl synchroniczny implementuje intuicyjny proces — wysłanie żądania, poczekanie na odpowiedź, wysłanie następnego żądania itd. Metoda createWebCustomerDocumentsIfNotExist
nie stosuje jednak tego podejścia, ponieważ blokowanie wywołań będzie zasadniczo utratą cykli procesora CPU w trakcie czasu odpowiedzi na żądanie, co spowoduje niską liczbę żądań na sekundę.
Aby uniknąć tego problemu związanego z niską liczbą żądań na sekundę, możesz zduplikować kilka wątków, by umożliwić wykonywanie równoległych wywoływań żądań blokowania. Zduplikowane wątki skrócą czas wykonywania żądania. Jednak jeśli chcesz zaoszczędzić zasoby wątków, takie rozwiązanie również będzie nieekonomiczne. Każdy wątek wykonuję pętlę w trakcie czasu odpowiedzi na żądanie, gdy zamiast tego mógłby wykonywać wiele innych zadań jednocześnie, dając niską ilość żądań na sekundę na wątek.
Z tego powodu, oraz w celu pokazania wydajnego wątkowo wstawiania klas POJO języka Java, udostępniliśmy asynchroniczny przykład wstawiania dokumentu. Obsługa asynchroniczna projektu Spring Data pochodzi z rozwiązania Project Reactor, struktury aplikacji języka Java, która zapewnia oparty na strumieniu model programowania deklaratywnego przepływu danych umożliwiający programowanie oparte na zdarzeniach asynchronicznych. Metoda createWebCustomerDocumentsIfNotExist
implementuje programowanie asynchroniczne biblioteki Project Reactor.
W metodzie createWebCustomerDocumentsIfNotExist
Flux.fromIterable(webCustomers)
jest metodą tworzącą biblioteki Project Reactor. Tworzy wystąpienie klasy Flux
, które jest źródłem zdarzeń asynchronicznych. W tym przypadku każde „zdarzenie” asynchroniczne zawiera argument wystąpienia klasy WebCustomer
. Wystąpienie klasy Flux
zawiera dwa takie zdarzenia — jedno dla wystąpienia maxaxam i jedno dla wystąpienia nelapin. Kod metody .flatMap( ... ).blockLast();
definiuje potok operacji sekwencyjnych, które należy wykonać na zdarzeniach emitowanych przez wystąpienie klasy Flux
.
W takim przypadku dwie operacje w potoku są wywołaniami elementu save
. Ten potok jest niemal identyczny do modelu synchronicznego, z tą różnicą, że nie wywołanie operacji save
nie jest blokujące. Wywołanie metody blockLast()
powoduje subskrypcję przygotowanego potoku, przez co wystąpienie Flux
asynchronicznie emituje oba swoje zdarzenia. Następnie potok wewnątrz elementu .flatMap( ... ).blockLast();
przetwarza każde z tych zdarzeń w sposób pseudo-równoległy. Gdy jedno żądanie jest wystawiane i czeka na odpowiedź, biblioteka Project Reactor będzie przetwarzać inne żądania w tle, co jest krytycznym czynnikiem w maksymalizacji liczby żądań na sekundę na wątek.
Skoro poznaliśmy już wydajne asynchroniczne żądania bazy danych za pomocą biblioteki Project Reactor, dla uproszczenia w pozostałej części tego laboratorium będziemy używać wywołań blokujących asynchronicznych (a w rzeczywistości wywołań synchronicznych). Aby dowiedzieć się więcej na temat biblioteki Project Reactor, zobacz Przewodnik po wzorcu biblioteki Reactor usługi Azure Cosmos DB.
Czytanie dokumentów
W celu odczytu dokumentów z bazy danych, dodaj następującą metodę do klasy
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; }
Skopiuj i wklej następujący kod na końcu metody
run
po kodzie tworzenia dokumentu:readWebCustomerDocument(maxaxam);
Skompiluj i uruchom plik CosmosSample.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn spring-boot:run
Oprócz danych wyjściowych terminalu powinny zostać wyświetlone poniższe dane. „Read user 1” (Odczyt — użytkownik 1) oznacza, że dokument został pobrany.
INFO: Read webCustomer 1
Usuwanie dokumentów
Skopiuj i wklej metodę
deleteWebCustomerDocument
pod metodą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()); } }
Skopiuj i wklej następujący kod na końcu metody
run
.deleteWebCustomerDocument(maxaxam);
Skompiluj i uruchom plik CosmosSample.java w środowisku IDE lub uruchom program w terminalu przy użyciu polecenia:
mvn clean package mvn spring-boot:run
Oprócz danych wyjściowych terminalu powinny zostać wyświetlone poniższe dane. „Deleted user 1” (Usunięto — użytkownik 1) oznacza, że dokument został usunięty.
INFO: Deleted webCustomer 1
W tej lekcji utworzyliśmy, zaktualizowaliśmy, odczytaliśmy i usunęliśmy dokumenty w bazie danych usługi Azure Cosmos DB.