Udostępnij za pomocą


Migrowanie aplikacji do korzystania z zestawu Java SDK usługi Azure Cosmos DB w wersji 4

DOTYCZY: NoSQL

Ważne

Aby uzyskać więcej informacji na temat tego zestawu SDK, zapoznaj się z informacjami o wersji zestawu Java SDK usługi Azure Cosmos DB w wersji 4, repozytorium Maven, wskazówkami dotyczącymi wydajności zestawu Java SDK w wersji 4 usługi Azure Cosmos DB i przewodnikiem rozwiązywania problemów z zestawem Java SDK usługi Azure Cosmos DB w wersji 4.

Ważne

Ponieważ zestaw Java SDK usługi Azure Cosmos DB w wersji 4 ma do 20% zwiększoną przepływność, tryb bezpośredni oparty na protokole TCP i obsługę najnowszych funkcji usługi zaplecza, zalecamy uaktualnienie do wersji 4 przy następnej okazji. Kontynuuj czytanie poniżej, aby dowiedzieć się więcej.

Zaktualizuj do najnowszego zestawu Java SDK dla usługi Azure Cosmos DB, aby w pełni skorzystać z jej najlepszych możliwości — zarządzanej usługi nierelacyjnej bazy danych o konkurencyjnej wydajności, dostępności na poziomie 99.999%, unikalnego zarządzania zasobami i nie tylko. W tym artykule wyjaśniono, jak uaktualnić istniejącą aplikację Java korzystającą ze starszego zestawu JAVA SDK usługi Azure Cosmos DB do nowszego zestawu Java SDK usługi Azure Cosmos DB 4.0 dla interfejsu API for NoSQL. Zestaw Java SDK usługi Azure Cosmos DB w wersji 4 odpowiada pakietowi com.azure.cosmos . Instrukcje podane w tym dokumencie można wykonać, jeśli migrujesz aplikację z dowolnego z następujących zestawów SDK Języka Java usługi Azure Cosmos DB:

  • Synchronizowanie zestawu Java SDK 2.x.x
  • Async Java SDK 2.x.x
  • Java SDK 3.x.x

Mapowania pakietów i zestawu Java SDK usługi Azure Cosmos DB

W poniższej tabeli wymieniono różne zestawy SDK java usługi Azure Cosmos DB, nazwę pakietu i informacje o wersji:

Java SDK Data wydania Zestawione interfejsy API Maven Jar Nazwa pakietu Java Dokumentacja API Informacje o wersji Data wycofania
Async 2.x.x czerwiec 2018 Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Informacje o wersji 31 sierpnia 2024 r.
Synchronizacja 2.x.x Wrzesień 2018 r. Synchronizuj com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API czwartek, 29 lutego 2024 r.
3.x.x Lipiec 2019 Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 31 sierpnia 2024 r.
4.0 Czerwiec 2020 Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

Zmiany implementacji na poziomie zestawu SDK

Poniżej przedstawiono kluczowe różnice implementacji między różnymi zestawami SDK:

Biblioteka RxJava została zastąpiona przez bibliotekę Reactor w Java SDK dla Azure Cosmos DB w wersjach 3.x.x i 4.0

Jeśli nie znasz programowania asynchronicznego lub programowania reaktywnego, zapoznaj się z przewodnikiem po wzorcu Reactor, aby zapoznać się z wprowadzeniem do programowania asynchronicznego i projektu Reactor. Ten przewodnik może być przydatny, jeśli w przeszłości używałeś pakietu Azure Cosmos DB Sync Java SDK 2.x.x lub pakietu Azure Cosmos DB Java SDK 3.x.x Sync API.

Jeśli używasz zestawu Azure Cosmos DB Async Java SDK 2.x.x i planujesz migrację do zestawu SDK w wersji 4.0, zapoznaj się z przewodnikiem Reactor vs RxJava, aby uzyskać wskazówki dotyczące konwertowania kodu RxJava na korzystanie z biblioteki Reactor.

Java SDK dla Azure Cosmos DB w wersji 4 ma tryb połączenia bezpośredniego zarówno w API asynchronicznych, jak i w API synchronicznych.

Jeśli używasz zestawu Java SDK 2.x.x usługi Azure Cosmos DB, należy pamiętać, że tryb bezpośredniego połączenia na podstawie protokołu TCP (w przeciwieństwie do protokołu HTTP) jest implementowany w zestawie Java SDK 4.0 usługi Azure Cosmos DB dla interfejsów API asynchronicznych i synchronizacji.

Zmiany na poziomie interfejsu API

Poniżej przedstawiono zmiany na poziomie interfejsu API w zestawie Java SDK 4.x.x usługi Azure Cosmos DB w porównaniu z poprzednimi zestawami SDK (zestaw Java SDK 3.x.x, zestaw Async Java SDK 2.x.x i zestaw Java SDK synchronizacji 2.x.x):

Konwencje nazewnictwa zestawu Java SDK usługi Azure Cosmos DB

  • Zestaw Java SDK usługi Azure Cosmos DB w wersjach 3.x.x i 4.0 nazywa zasoby klienta jako Cosmos<resourceName>. Na przykład , CosmosClient, CosmosDatabase, CosmosContainer. Podczas gdy w wersji 2.x.x zestawy SDK języka Java usługi Azure Cosmos DB nie mają jednolitego schematu nazewnictwa.

  • SDK Java 3.x.x i 4.0 dla usługi Azure Cosmos DB oferują zarówno synchronizowane, jak i asynchroniczne interfejsy API.

    • Java SDK 4.0 : wszystkie klasy należą do API synchronizacji, chyba że do nazwy klasy zostanie dodane Async po Cosmos.

    • Java SDK 3.x.x: wszystkie klasy należą do Async API, chyba że do nazwy klasy zostanie dołączone Async po Cosmos.

    • Async Java SDK 2.x.x: Nazwy klas są podobne do Sync Java SDK 2.x.x, jednak nazwa zaczyna się od Async.

Hierarchiczna struktura interfejsu API

Zestaw Java SDK usługi Azure Cosmos DB w wersji 4.0 i 3.x.x wprowadza hierarchiczną strukturę interfejsu API, która organizuje klientów, bazy danych i kontenery w sposób zagnieżdżony, jak pokazano w poniższym fragmencie kodu zestawu SDK w wersji 4.0:

CosmosContainer container = client.getDatabase("MyDatabaseName").getContainer("MyContainerName");

W wersji 2.x.x Azure Cosmos DB Java SDK wszystkie operacje na zasobach i dokumentach są wykonywane za pośrednictwem instancji klienta.

Reprezentowanie dokumentów

W pakiecie Java SDK 4.0 dla usługi Azure Cosmos DB niestandardowe obiekty POJO i JsonNodes są dwiema opcjami do odczytywania i zapisywania dokumentów z usługi Azure Cosmos DB.

W wersji 3.x.x zestawu Java SDK usługi Azure Cosmos DB, obiekt CosmosItemProperties jest udostępniany przez publiczny interfejs API i służy jako reprezentacja dokumentu. Ta klasa nie jest już uwidoczniona publicznie w wersji 4.0.

Operacje importu

  • Pakiety zestawu Java SDK 4.0 usługi Azure Cosmos DB zaczynają się od com.azure.cosmos

  • Pakiety zestawu Java SDK 3.x.x usługi Azure Cosmos DB zaczynają się od com.azure.data.cosmos

  • Pakiety synchronizującego interfejsu API Java SDK 2.x.x usługi Azure Cosmos DB zaczynają się od com.microsoft.azure.documentdb

  • Zestaw Java SDK usługi Azure Cosmos DB 4.0 umieszcza kilka klas w zagnieżdżonym pakiecie com.azure.cosmos.models. Niektóre z tych pakietów to:

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • Analogia interfejsu API asynchronicznego dla wszystkich powyższych pakietów
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode ... itd.

Akcesory

Język Java SDK usługi Azure Cosmos DB w wersji 4.0 udostępnia metody get i set do uzyskiwania dostępu do składowych instancji. Na przykład instancja CosmosContainer ma metody container.getId() i container.setId().

Różni się to od zestawu Java SDK usługi Azure Cosmos DB 3.x.x, który uwidacznia płynny interfejs. Na przykład, wystąpienie CosmosSyncContainer ma metodę container.id(), która jest przeciążona, aby pobrać lub ustawić wartość id.

Zarządzanie konfliktami zależności

Uaktualnienie z wersji 2 do wersji 4 Java SDK usługi Azure Cosmos DB może prowadzić do konfliktów zależności ze względu na zmiany w bibliotekach używanych przez SDK. Rozwiązywanie tych konfliktów wymaga starannego zarządzania zależnościami.

  1. Poznaj nowe zależności: zestaw SDK usługi Azure Cosmos DB w wersji 4 ma własny zestaw zależności, które mogą się różnić od tych w poprzednich wersjach. Upewnij się, że znasz te zależności:

    • azure-cosmos
    • reactor-core
    • reactor-netty
    • netty-handler
    • guava
    • slf4j-api
    • jackson-databind
    • jackson-annotations
    • jackson-core
    • commons-lang3
    • commons-collections4
    • azure-core
    • azure-core-http-netty
  2. Usuń zależności powodujące konflikt: zacznij od usunięcia zależności powiązanych z poprzednimi wersjami zestawu SDK z pliku pom.xml . Obejmują azure-cosmosdb oraz wszystkie przejściowe zależności, które mógł mieć stary zestaw SDK.

  3. Dodaj zależności V4 SDK: Dodaj zestaw SDK w wersji 4 i jego zależności do pom.xml. Oto przykład:

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
        <version>4.x.x</version> <!-- Use the latest version available -->
    </dependency>
    
  4. Sprawdź konflikty zależności: użyj polecenia Maven dependency:tree , aby wygenerować drzewo zależności i zidentyfikować wszelkie konflikty. Uruchom:

    mvn dependency:tree
    

    Wyszukaj wszelkie sprzeczne wersje zależności. Te konflikty często występują z bibliotekami, takimi jak reactor-core, netty-handler, guavai jackson.

  5. Użyj zarządzania zależnościami: jeśli wystąpią konflikty wersji, może być konieczne zastąpienie problematycznych wersji, korzystając z sekcji <dependencyManagement> w pliku pom.xml. Oto przykład wymuszania określonej wersji elementu reactor-core:

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>io.projectreactor</groupId>
                <artifactId>reactor-core</artifactId>
                <version>3.x.x</version> <!-- Use a compatible version -->
            </dependency>
            <!-- Repeat for any other conflicting dependencies -->
        </dependencies>
    </dependencyManagement>
    
  6. Wyklucz przejściowe zależności: czasami może być konieczne wykluczenie zależności przechodnich wprowadzonych przez inne zależności. Jeśli na przykład inna biblioteka wprowadza starszą wersję zależności, która powoduje konflikt, możesz ją wykluczyć w następujący sposób:

    <dependency>
        <groupId>some.group</groupId>
        <artifactId>some-artifact</artifactId>
        <version>x.x.x</version>
        <exclusions>
            <exclusion>
                <groupId>conflicting.group</groupId>
                <artifactId>conflicting-artifact</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  7. Kompilowanie i testowanie: po wprowadzeniu tych zmian ponownie skompiluj projekt i dokładnie przetestuj go, aby upewnić się, że nowe zależności działają poprawnie i że nie występują konflikty środowiska uruchomieniowego.

Porównania fragmentów kodu

Tworzenie zasobów

Poniższy fragment kodu przedstawia różnice w sposobie tworzenia zasobów między interfejsami API 4.0, 3.x.x, 2.x.x Sync i 2.x.x Async.


// Create Async client.
// Building an async client is still a sync operation.
CosmosAsyncClient client = new CosmosClientBuilder()
        .endpoint("your.hostname")
        .key("yourmasterkey")
        .consistencyLevel(ConsistencyLevel.EVENTUAL)
        .buildAsyncClient();

// Create database with specified name
client.createDatabaseIfNotExists("YourDatabaseName")
        .flatMap(databaseResponse -> {
            testDatabaseAsync = client.getDatabase("YourDatabaseName");
            // Container properties - name and partition key
            CosmosContainerProperties containerProperties =
                    new CosmosContainerProperties("YourContainerName", "/id");

            // Provision manual throughput
            ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);

            // Create container
            return database.createContainerIfNotExists(containerProperties, throughputProperties);
        }).flatMap(containerResponse -> {
    testContainerAsync = database.getContainer("YourContainerName");
    return Mono.empty();
}).subscribe();

Operacje na elementach

Poniższy fragment kodu pokazuje różnice w sposobie wykonywania operacji elementów między interfejsami API 4.0, 3.x.x Asynchroniczne, 2.x.x Synchronizowane i 2.x.x Asynchroniczne.


// Container is created. Generate many docs to insert.
int number_of_docs = 50000;
ArrayList<JsonNode> docs = generateManyDocs(number_of_docs);

// Insert many docs into container...
Flux.fromIterable(docs)
        .flatMap(doc -> testContainerAsync.createItem(doc))
        .subscribe(); // ...Subscribing triggers stream execution.

Indeksowanie

Poniższy fragment kodu przedstawia różnice w tworzeniu indeksowania między interfejsami API 4.0, 3.x.x Async, 2.x.x Sync i 2.x.x Async.


CosmosContainerProperties containerProperties = new CosmosContainerProperties(containerName, "/lastName");

// Custom indexing policy
IndexingPolicy indexingPolicy = new IndexingPolicy();
indexingPolicy.setIndexingMode(IndexingMode.CONSISTENT);

// Included paths
List<IncludedPath> includedPaths = new ArrayList<>();
includedPaths.add(new IncludedPath("/*"));
indexingPolicy.setIncludedPaths(includedPaths);

// Excluded paths
List<ExcludedPath> excludedPaths = new ArrayList<>();
excludedPaths.add(new ExcludedPath("/name/*"));
indexingPolicy.setExcludedPaths(excludedPaths);

containerProperties.setIndexingPolicy(indexingPolicy);

ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);

database.createContainerIfNotExists(containerProperties, throughputProperties);
CosmosAsyncContainer containerIfNotExists = database.getContainer(containerName);

Procedury składowane

Poniższy fragment kodu pokazuje różnice w tworzeniu procedur składowanych między interfejsami API 4.0, 3.x.x Async, 2.x.x Sync i 2.x.x Async:


logger.info("Creating stored procedure...\n");

String sprocId = "createMyDocument";

String sprocBody = "function createMyDocument() {\n" +
        "var documentToCreate = {\"id\":\"test_doc\"}\n" +
        "var context = getContext();\n" +
        "var collection = context.getCollection();\n" +
        "var accepted = collection.createDocument(collection.getSelfLink(), documentToCreate,\n" +
        "    function (err, documentCreated) {\n" +
        "if (err) throw new Error('Error' + err.message);\n" +
        "context.getResponse().setBody(documentCreated.id)\n" +
        "});\n" +
        "if (!accepted) return;\n" +
        "}";

CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(sprocId, sprocBody);
container.getScripts()
        .createStoredProcedure(storedProcedureDef,
                new CosmosStoredProcedureRequestOptions()).block();

// ...

logger.info(String.format("Executing stored procedure %s...\n\n", sprocId));

CosmosStoredProcedureRequestOptions options = new CosmosStoredProcedureRequestOptions();
options.setPartitionKey(new PartitionKey("test_doc"));

container.getScripts()
        .getStoredProcedure(sprocId)
        .execute(null, options)
        .flatMap(executeResponse -> {
            logger.info(String.format("Stored procedure %s returned %s (HTTP %d), at cost %.3f RU.\n",
                    sprocId,
                    executeResponse.getResponseAsString(),
                    executeResponse.getStatusCode(),
                    executeResponse.getRequestCharge()));
            return Mono.empty();
        }).block();

Źródło zmian

Poniższy fragment kodu pokazuje różnice w sposobie wykonywania operacji strumienia zmian między asynchronicznymi interfejsami API 4.0 i 3.x.x.


ChangeFeedProcessor changeFeedProcessorInstance =
        new ChangeFeedProcessorBuilder()
                .hostName(hostName)
                .feedContainer(feedContainer)
                .leaseContainer(leaseContainer)
                .handleChanges((List<JsonNode> docs) -> {
                    logger.info("--->setHandleChanges() START");

                    for (JsonNode document : docs) {
                        try {
                            //Change Feed hands the document to you in the form of a JsonNode
                            //As a developer you have two options for handling the JsonNode document provided to you by Change Feed
                            //One option is to operate on the document in the form of a JsonNode, as shown below. This is great
                            //especially if you do not have a single uniform data model for all documents.
                            logger.info("---->DOCUMENT RECEIVED: " + OBJECT_MAPPER.writerWithDefaultPrettyPrinter()
                                    .writeValueAsString(document));

                            //You can also transform the JsonNode to a POJO having the same structure as the JsonNode,
                            //as shown below. Then you can operate on the POJO.
                            CustomPOJO pojo_doc = OBJECT_MAPPER.treeToValue(document, CustomPOJO.class);
                            logger.info("----=>id: " + pojo_doc.getId());

                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                        }
                    }
                    logger.info("--->handleChanges() END");

                })
                .buildChangeFeedProcessor();

// ...

changeFeedProcessorInstance.start()
        .subscribeOn(Schedulers.boundedElastic())
        .subscribe();

Czas życia (TTL) na poziomie kontenera

Poniższy fragment kodu pokazuje różnice w sposobie tworzenia czasu wygaśnięcia danych w kontenerze między 4.0, 3.x.x Async, 2.x.x Sync i 2.x.x Async API:


CosmosAsyncContainer container;

// Create a new container with TTL enabled with default expiration value
CosmosContainerProperties containerProperties = new CosmosContainerProperties("myContainer", "/myPartitionKey");
containerProperties.setDefaultTimeToLiveInSeconds(90 * 60 * 60 * 24);
ThroughputProperties throughputProperties = ThroughputProperties.createManualThroughput(400);
database.createContainerIfNotExists(containerProperties, throughputProperties).block();
container = database.getContainer("myContainer");

Czas życia na poziomie elementu (TTL)

Poniższy fragment kodu pokazuje różnice w tworzeniu czasu życia dla elementu pomiędzy API 4.0, 3.x.x Async, 2.x.x Sync i 2.x.x Async.


// Include a property that serializes to "ttl" in JSON
class SalesOrder
{
    private String id;
    private String customerId;
    private Integer ttl;

    public SalesOrder(String id, String customerId, Integer ttl) {
        this.id = id;
        this.customerId = customerId;
        this.ttl = ttl;
    }

    public String getId() {return this.id;}
    public void setId(String new_id) {this.id = new_id;}
    public String getCustomerId() {return this.customerId;}
    public void setCustomerId(String new_cid) {this.customerId = new_cid;}
    public Integer getTtl() {return this.ttl;}
    public void setTtl(Integer new_ttl) {this.ttl = new_ttl;}

    //...
}


// Set the value to the expiration in seconds
SalesOrder salesOrder = new SalesOrder(
        "SO05",
        "CO18009186470",
        60 * 60 * 24 * 30  // Expire sales orders in 30 days
);

Następne kroki