Migrera ditt program för att använda Azure Cosmos DB Java SDK v4

GÄLLER FÖR: NoSQL

Viktigt!

Mer information om denna SDK finns i Azure Cosmos DB Java SDK v4 Viktig information, Maven-lagringsplats, Azure Cosmos DB Java SDK v4-prestandatips och Felsökningsguide för Azure Cosmos DB Java SDK v4.

Viktigt!

Eftersom Azure Cosmos DB Java SDK v4 har upp till 20 % förbättrat dataflöde, TCP-baserat direktläge och stöd för de senaste funktionerna i serverdelstjänsten rekommenderar vi att du uppgraderar till v4 vid nästa tillfälle. Fortsätt läsa nedan om du vill veta mer.

Uppdatera till den senaste Azure Cosmos DB Java SDK för att få ut det bästa av vad Azure Cosmos DB har att erbjuda – en hanterad icke-relationell databastjänst med konkurrenskraftiga prestanda, femnios tillgänglighet, unik resursstyrning med mera. Den här artikeln beskriver hur du uppgraderar ditt befintliga Java-program som använder en äldre Azure Cosmos DB Java SDK till nyare Azure Cosmos DB Java SDK 4.0 för API för NoSQL. Azure Cosmos DB Java SDK v4 motsvarar com.azure.cosmos paketet. Du kan använda anvisningarna i det här dokumentet om du migrerar ditt program från någon av följande Azure Cosmos DB Java SDK:er:

  • Synkronisera Java SDK 2.x.x
  • Async Java SDK 2.x.x
  • Java SDK 3.x.x

Azure Cosmos DB Java SDK:s och paketmappningar

I följande tabell visas olika Java-SDK:er för Azure Cosmos DB, paketnamnet och versionsinformationen:

Java SDK Utgivningsdatum Paketerade API:er Maven Jar Java-paketnamn API-referens Viktig information Datum för borttagning
Async 2.x.x 2018 juni Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Viktig information 31 augusti 2024
Synkronisera 2.x.x Sept 2018 Synkronisera com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 29 februari 2024
3.x.x Juli 2019 Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 31 augusti 2024
4.0 Juni 2020 Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

Implementeringsändringar på SDK-nivå

Följande är de viktigaste implementeringsskillnaderna mellan olika SDK:er:

RxJava ersätts med reaktor i Azure Cosmos DB Java SDK version 3.x.x och 4.0

Om du inte känner till asynkron programmering eller reaktiv programmering kan du läsa Reaktormönsterguiden för en introduktion till asynkron programmering och Project Reactor. Den här guiden kan vara användbar om du tidigare har använt Azure Cosmos DB Sync Java SDK 2.x.x eller Azure Cosmos DB Java SDK 3.x.x Sync API.

Om du har använt Azure Cosmos DB Async Java SDK 2.x.x och planerar att migrera till 4.0 SDK kan du läsa guiden Reactor vs RxJava (Reaktor vs RxJava) för vägledning om hur du konverterar RxJava-kod till att använda Reactor.

Azure Cosmos DB Java SDK v4 har direktanslutningsläge i både Async- och Sync-API:er

Om du har använt Azure Cosmos DB Sync Java SDK 2.x.x bör du tänka på att direktanslutningsläget baserat på TCP (i stället för HTTP) implementeras i Azure Cosmos DB Java SDK 4.0 för både Async- och Sync-API:erna.

Ändringar på API-nivå

Följande är ändringar på API-nivå i Azure Cosmos DB Java SDK 4.x.x jämfört med tidigare SDK:er (Java SDK 3.x.x, Async Java SDK 2.x.x och Sync Java SDK 2.x.x):

Namngivningskonventioner för Azure Cosmos DB Java SDK

  • Azure Cosmos DB Java SDK 3.x.x och 4.0 refererar till klientresurserna som Cosmos<resourceName>. Till exempel CosmosClient, CosmosDatabase, CosmosContainer. I version 2.x.x har Azure Cosmos DB Java SDK:er inte något enhetligt namngivningsschema.

  • Azure Cosmos DB Java SDK 3.x.x och 4.0 erbjuder både Sync- och Async-API:er.

    • Java SDK 4.0 : Alla klasser tillhör Synkroniserings-API:et om inte klassnamnet läggs till efter Async Cosmos.

    • Java SDK 3.x.x: Alla klasser tillhör Async-API:et om inte klassnamnet läggs till efter Async Cosmos.

    • Async Java SDK 2.x.x: Klassnamnen liknar Sync Java SDK 2.x.x, men namnet börjar med Async.

Hierarkisk API-struktur

Azure Cosmos DB Java SDK 4.0 och 3.x.x introducerar en hierarkisk API-struktur som organiserar klienter, databaser och containrar på ett kapslat sätt enligt följande kodfragment på 4,0 SDK:

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

I version 2.x.x av Azure Cosmos DB Java SDK utförs alla åtgärder på resurser och dokument via klientinstansen.

Representerar dokument

I Azure Cosmos DB Java SDK 4.0 är anpassade POJO:er och JsonNodes de två alternativen för att läsa och skriva dokumenten från Azure Cosmos DB.

I Azure Cosmos DB Java SDK 3.x.x CosmosItemProperties exponeras objektet av det offentliga API:et och hanteras som en dokumentrepresentation. Den här klassen exponeras inte längre offentligt i version 4.0.

Importer

  • Azure Cosmos DB Java SDK 4.0-paketen börjar med com.azure.cosmos

  • Azure Cosmos DB Java SDK 3.x.x-paket börjar med com.azure.data.cosmos

  • Azure Cosmos DB Java SDK 2.x.x Sync API-paket börjar med com.microsoft.azure.documentdb

  • Azure Cosmos DB Java SDK 4.0 placerar flera klasser i ett kapslat paket com.azure.cosmos.models. Några av dessa paket är:

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • Async API-analoger för alla ovanstående paket
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode ... etc.

Accessors

Azure Cosmos DB Java SDK 4.0 exponerar get och set metoder för åtkomst till instansmedlemmarna. Till exempel har container.getId() instansen CosmosContainer och container.setId() metoder.

Detta skiljer sig från Azure Cosmos DB Java SDK 3.x.x som exponerar ett fluent-gränssnitt. Till exempel har container.id() en CosmosSyncContainer instans som är överbelastad för att hämta eller ange id värdet.

Hantera beroendekonflikter

Uppgradering från Azure Cosmos DB Java SDK V2 till V4 kan medföra beroendekonflikter på grund av ändringar i de bibliotek som används av SDK. För att lösa dessa konflikter krävs noggrann hantering av beroendena.

  1. Förstå de nya beroendena: Azure Cosmos DB V4 SDK har en egen uppsättning beroenden som kan skilja sig från dem i tidigare versioner. Kontrollera att du är medveten om dessa beroenden:

    • 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. Ta bort beroenden i konflikt: Börja med att ta bort beroenden som är relaterade till tidigare versioner av SDK:t från filen pom.xml . Dessa inkluderar azure-cosmosdb och eventuella transitiva beroenden som det gamla SDK:et kan ha haft.

  3. Lägg till V4 SDK-beroenden: Lägg till V4 SDK och dess beroenden i din pom.xml. Här är ett exempel:

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
        <version>4.x.x</version> <!-- Use the latest version available -->
    </dependency>
    
  4. Sök efter beroendekonflikter: Använd Maven-kommandot dependency:tree för att generera ett beroendeträd och identifiera eventuella konflikter. Kör:

    mvn dependency:tree
    

    Leta efter eventuella motstridiga versioner av beroenden. Dessa konflikter uppstår ofta med bibliotek som reactor-core, netty-handler, guavaoch jackson.

  5. Använd Beroendehantering: Om du stöter på versionskonflikter kan du behöva åsidosätta problematiska versioner med hjälp av <dependencyManagement> avsnittet i din pom.xml. Här är ett exempel för att framtvinga en specifik version av 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. Exkludera transitiva beroenden: Ibland kan du behöva undanta transitiva beroenden som har tagits in av andra beroenden. Om ett annat bibliotek till exempel innehåller en äldre version av ett beroende som står i konflikt kan du exkludera det så här:

    <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. Återskapa och testa: När du har gjort dessa ändringar återskapar du projektet och testar det noggrant för att säkerställa att de nya beroendena fungerar korrekt och att inga körningskonflikter inträffar.

Jämförelse av kodfragment

Skapa resurser

Följande kodfragment visar skillnaderna i hur resurser skapas mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 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();

Objektåtgärder

Följande kodfragment visar skillnaderna i hur objektåtgärder utförs mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 2.x.x Async:


// 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.

Indexering

Följande kodfragment visar skillnaderna i hur indexering skapas mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 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);

Lagrade procedurer

Följande kodfragment visar skillnaderna i hur lagrade procedurer skapas mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 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();

Ändringsfeed

Följande kodfragment visar skillnaderna i hur ändringsflödesåtgärder körs mellan API:erna 4.0 och 3.x.x Async:


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.elastic())
        .subscribe();

Time-To-Live(TTL) på containernivå

Följande kodfragment visar skillnaderna i hur du skapar tid att leva för data i containern mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 2.x.x Async:


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");

Tid till live(TTL) på objektnivå

Följande kodfragment visar skillnaderna i hur du skapar tid att leva för ett objekt mellan API:erna 4.0, 3.x.x Async, 2.x.x Sync och 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
);

Nästa steg