Partilhar via


Migre a sua aplicação para usar o Azure Cosmos DB Java SDK v4

Importante

Para mais informações sobre este SDK, consulte as notas de versão do Azure Cosmos DB Java SDK v4, o repositório Maven, dicas de desempenho do Azure Cosmos DB Java SDK v4 e o guia de resolução de problemas do Azure Cosmos DB Java SDK v4.

Importante

Como o Azure Cosmos DB Java SDK v4 tem até 20% de rendimento melhorado, modo direto baseado em TCP e suporte para as mais recentes funcionalidades de serviço backend, recomendamos que atualize para a v4 assim que puder. Continue a ler abaixo para saber mais.

Atualize para o mais recente Azure Cosmos DB Java SDK para obter o melhor que o Azure Cosmos DB tem para oferecer — um serviço de base de dados não relacional gerido, oferecendo desempenho competitivo, disponibilidade de 99,999%, governação de recursos única e muito mais. Este artigo explica como atualizar a sua aplicação Java existente que utiliza um antigo Azure Cosmos DB Java SDK para o mais recente Azure Cosmos DB Java SDK 4.0 para API para NoSQL. O Azure Cosmos DB Java SDK v4 corresponde ao com.azure.cosmos pacote. Pode usar as instruções neste documento se estiver a migrar a sua aplicação a partir de qualquer um dos seguintes SDKs Java do Azure Cosmos DB:

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

Azure Cosmos DB Java SDKs e mapeamentos de pacotes

A tabela seguinte lista diferentes SDKs Java do Azure Cosmos DB, o nome do pacote e as informações de lançamento:

SDK de Java Data de Lançamento APIs agrupadas Maven Jar Nome do pacote Java Referência da API Notas de lançamento Data de desativação
Async 2.x.x Junho de 2018 Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Notas de versão 31 de agosto de 2024
Sync 2.x.x Set. 2018 Sincronização com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 29 de fevereiro de 2024
3.x.x Julho de 2019 Async (Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 31 de agosto de 2024
4.0 Junho de 2020 Async (Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

Alterações de implementação ao nível do SDK

Seguem-se as principais diferenças de implementação entre diferentes SDKs:

O RxJava foi substituído pelo reactor no Azure Cosmos DB Java SDK versões 3.x.x e 4.0

Se não estiver familiarizado com programação assíncrona ou Programação Reativa, consulte o guia de padrões Reactor para uma introdução à programação assíncrona e ao Project Reactor. Este guia pode ser útil se já usou Azure Cosmos DB Sync Java SDK 2.x.x ou Azure Cosmos DB Java SDK 3.x.x Sync API no passado.

Se tem usado Azure Cosmos DB Async Java SDK 2.x.x e planeia migrar para o SDK 4.0, consulte o Guia Reactor vs RxJava para orientações sobre como converter código RxJava para usar Reactor.

O Azure Cosmos DB Java SDK v4 tem modo de conectividade direta tanto na API Assíncrona como na Sync

Se tem usado o Azure Cosmos DB Sync Java SDK 2.x.x, note que o modo de ligação direta baseado em TCP (em oposição a HTTP) está implementado no Azure Cosmos DB Java SDK 4.0 tanto para as APIs Assíncronas como Sync.

Alterações ao nível da API

Seguem-se as alterações ao nível da API no Azure Cosmos DB Java SDK 4.x.x em comparação com SDKs anteriores (Java SDK 3.x.x, Async Java SDK 2.x.x e Sync Java SDK 2.x.x):

Convenções de nomenclatura Azure Cosmos DB Java SDK

  • O Azure Cosmos DB Java SDK 3.x.x e 4.0 refere-se aos recursos do cliente como Cosmos<resourceName>. Por exemplo, CosmosClient, , CosmosDatabaseCosmosContainer. Enquanto que na versão 2.x.x, os SDKs Java do Azure Cosmos DB não têm um esquema de nomenclatura uniforme.

  • O Azure Cosmos DB Java SDK 3.x.x e 4.0 oferece APIs Sync e Assíncronas.

    • Java SDK 4.0 : Todas as classes pertencem à API de Sincronização, a menos que o nome da classe seja adicionado após AsyncCosmos.

    • Java SDK 3.x.x: Todas as classes pertencem à API Assíncrona, a menos que o nome da classe seja adicionado após AsyncCosmos.

    • Async Java SDK 2.x.x: Os nomes das classes são semelhantes ao Sync Java SDK 2.x.x, no entanto o nome começa por Async.

Estrutura hierárquica de API

O Azure Cosmos DB Java SDK 4.0 e 3.x.x introduzem uma estrutura hierárquica de API que organiza os clientes, bases de dados e contentores de forma aninhada, como mostrado no seguinte excerto de código do SDK 4.0:

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

Na versão 2.x.x do Azure Cosmos DB Java SDK, todas as operações sobre recursos e documentos são realizadas através da instância cliente.

Representação de documentos

No Azure Cosmos DB Java SDK 4.0, POJOs personalizados e JsonNodes são as duas opções para ler e escrever os documentos a partir do Azure Cosmos DB.

No Azure Cosmos DB Java SDK 3.x.x, o CosmosItemProperties objeto é exposto pela API pública e servido como representação do documento. Esta classe já não é publicamente divulgada na versão 4.0.

Importações

  • Os pacotes Azure Cosmos DB Java SDK 4.0 começam com com.azure.cosmos

  • Os pacotes Azure Cosmos DB Java SDK 3.x.x começam com com.azure.data.cosmos

  • Azure Cosmos DB Java SDK 2.x.x Os pacotes API de sincronização começam com com.microsoft.azure.documentdb

  • O Azure Cosmos DB Java SDK 4.0 coloca diversas classes num pacote com.azure.cosmos.models aninhado. Alguns destes pacotes incluem:

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • Os análogos da API Assíncrona para todos os pacotes acima
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode ... etc.

Accessors

O Azure Cosmos DB Java SDK 4.0 expõe get e set métodos para aceder aos membros da instância. Por exemplo, a CosmosContainer instância tem container.getId() e container.setId() métodos.

Isto é diferente do Azure Cosmos DB Java SDK 3.x.x, que expõe uma interface fluente. Por exemplo, uma CosmosSyncContainer instância tem container.id() que está sobrecarregada para obter ou definir o id valor.

Gestão de Conflitos de Dependência

A atualização do Azure Cosmos DB Java SDK V2 para V4 pode introduzir conflitos de dependência devido a alterações nas bibliotecas usadas pelo SDK. Resolver estes conflitos requer uma gestão cuidadosa das dependências.

  1. Compreenda as Novas Dependências: O SDK Azure Cosmos DB V4 tem o seu próprio conjunto de dependências que podem ser diferentes das versões anteriores. Certifique-se de que está ciente destas dependências:

    • 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. Remover Dependências Conflitantes: Comece por remover as dependências relacionadas com versões anteriores do SDK do seu pom.xml ficheiro. Estas incluem azure-cosmosdb e quaisquer dependências transitivas que o antigo SDK possa ter tido.

  3. Adicione Dependências do SDK V4: Adicione o SDK V4 e as suas dependências ao seu pom.xmlarquivo. Aqui está um exemplo:

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
        <version>4.x.x</version> <!-- Use the latest version available -->
    </dependency>
    
  4. Verifique Conflitos de Dependências: Use o comando Maven dependency:tree para gerar uma árvore de dependências e identificar quaisquer conflitos. Executar:

    mvn dependency:tree
    

    Procura quaisquer versões conflitantes de dependências. Estes conflitos ocorrem frequentemente com bibliotecas como reactor-core, netty-handler, guava, e jackson.

  5. Use a gestão de dependências: Se encontrar conflitos de versões, poderá precisar de substituir versões problemáticas usando a secção no seu ficheiro pom.xml. Aqui está um exemplo para aplicar uma versão específica de 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. Exclua Dependências Transitivas: Por vezes, pode ser necessário excluir dependências transitivas trazidas por outras dependências. Por exemplo, se outra biblioteca trouxer uma versão mais antiga de uma dependência que entre em conflito, pode excluí-la assim:

    <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. Reconstruir e Testar: Depois de fazer estas alterações, reconstrua o seu projeto e teste-o minuciosamente para garantir que as novas dependências funcionam corretamente e que não ocorrem conflitos em tempo de execução.

Comparações de excertos de código

Criar recursos

O seguinte excerto de código mostra as diferenças na forma como os recursos são criados entre as APIs 4.0, 3.x.x Async, 2.x.x Sync e 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();

Operações de itens

O seguinte excerto de código mostra as diferenças na forma como as operações dos itens são realizadas entre as APIs Assíncronas 4.0, 3.x.x, e 2.x.x, assim como a API Sincronas 2.x.x:


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

Indexação

O seguinte excerto de código mostra as diferenças na forma como a indexação é criada entre as APIs Assíncronas 4.0, 3.x.x, 2.x.x Sync e 2.x.x Assíncronas:


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

Procedimentos armazenados

O seguinte excerto de código mostra as diferenças na forma como os procedimentos armazenados são criados entre as APIs 4.0, 3.x.x Assíncrona, 2.x.x Síncrona e 2.x.x Assíncrona:


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

Feed de alterações

O seguinte excerto de código mostra as diferenças na forma como as operações de fluxo de alterações são executadas entre as APIs Assíncronas 4.0 e 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();

Tempo para Viver ao nível do contentor (TTL)

O seguinte excerto de código mostra as diferenças na forma de criar tempo de vida para os dados no contentor entre as APIs 4.0, 3.x.x Async, 2.x.x Sync e 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");

Tempo para Viver ao nível do item (TTL)

O seguinte excerto de código mostra as diferenças na forma de criar tempo de vida para um item entre as APIs 4.0, 3.x.x Async, 2.x.x Sync e 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
);

Próximos passos