Compartir a través de


Migración de la aplicación para usar el SDK de Java de Azure Cosmos DB v4

Importante

Para más información sobre este SDK, consulte las notas de la versión v4 del SDK de Java de Azure Cosmos DB, el repositorio de Maven, las sugerencias de rendimiento del SDK de Java de Azure Cosmos DB v4 y la guía de solución de problemas del SDK de Java de Azure Cosmos DB v4.

Importante

Dado que el SDK de Java de Azure Cosmos DB v4 tiene hasta 20% rendimiento mejorado, el modo directo basado en TCP y la compatibilidad con las características más recientes del servicio back-end, se recomienda actualizar a v4 en la próxima oportunidad. Siga leyendo a continuación para obtener más información.

Actualice al SDK de Java más reciente de Azure Cosmos DB para obtener lo mejor de lo que Azure Cosmos DB tiene que ofrecer: un servicio de base de datos no relacional administrado con rendimiento competitivo, disponibilidad de cinco nueves, gestión de recursos única en su tipo, etc. En este artículo se explica cómo actualizar la aplicación Java existente que usa un SDK de Java de Azure Cosmos DB anterior a la versión más reciente del SDK de Java de Azure Cosmos DB 4.0 para API para NoSQL. El SDK de Java de Azure Cosmos DB v4 corresponde al com.azure.cosmos paquete. Puede usar las instrucciones de este documento si va a migrar la aplicación desde cualquiera de los siguientes SDK de Java de Azure Cosmos DB:

  • Sincronización del SDK de Java 2.x.x
  • SDK de Java asincrónico 2.x.x
  • SDK de Java 3.x.x

Asignaciones de paquetes y sdk de Java de Azure Cosmos DB

En la tabla siguiente se enumeran diferentes SDK de Java de Azure Cosmos DB, el nombre del paquete y la información de versión:

SDK de Java Fecha de lanzamiento API agrupadas Maven Jar Nombre del paquete de Java Referencia de API Notas de lanzamiento Fecha de retirada
Async 2.x.x Junio de 2018 Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Notas de lanzamiento 31 de agosto de 2024
Sync 2.x.x Septiembre de 2018 Sincronizar com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 29 de febrero de 2024
3.x.x Julio de 2019 Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 31 de agosto de 2024
4,0 Junio de 2020 Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

Cambios de implementación de nivel de SDK

A continuación se muestran las principales diferencias de implementación entre los distintos SDK:

RxJava se reemplaza por reactor en las versiones 3.x.x.x y 4.0 del SDK de Java de Azure Cosmos DB.

Si no está familiarizado con la programación asincrónica o la programación reactiva, consulte la guía de patrones de Reactor para obtener una introducción a la programación asincrónica y Project Reactor. Esta guía puede resultar útil si ha estado usando el SDK de Java de Sincronización de Azure Cosmos DB 2.x.x o la API de sincronización de Java de Azure Cosmos DB 3.x.x en el pasado.

Si ha estado usando el SDK de Java asincrónico de Azure Cosmos DB 2.x.x y planea migrar al SDK 4.0, consulte la Guía de Reactor frente a RxJava para obtener instrucciones sobre cómo convertir código RxJava para usar Reactor.

El SDK de Java de Azure Cosmos DB v4 tiene el modo de conectividad directa en las API asincrónicas y de sincronización.

Si ha estado usando el SDK de Java de Sincronización de Azure Cosmos DB 2.x.x, tenga en cuenta que el modo de conexión directa basado en TCP (en lugar de HTTP) se implementa en el SDK de Java de Azure Cosmos DB 4.0 para las API asincrónicas y de sincronización.

Cambios en el nivel de API

A continuación se muestran los cambios de nivel de API en el SDK de Java de Azure Cosmos DB 4.x.x en comparación con los SDK anteriores (SDK de Java 3.x.x, SDK de Java asincrónico 2.x.x y Sync Java SDK 2.x.x):

Convenciones de nomenclatura del SDK de Java de Azure Cosmos DB

  • El SDK de Java de Azure Cosmos DB 3.x.x y 4.0 hacen referencia a los recursos de cliente como Cosmos<resourceName>. Por ejemplo, CosmosClient, CosmosDatabase, CosmosContainer. Mientras que en la versión 2.x.x, los SDK de Java de Azure Cosmos DB no tienen un esquema de nomenclatura uniforme.

  • El SDK de Java de Azure Cosmos DB 3.x.x y 4.0 ofrecen las API sincronizadas y asincrónicas.

    • SDK de Java 4.0 : Todas las clases pertenecen a la API de sincronización a menos que el nombre de la clase se anexe con Async después de Cosmos.

    • SDK de Java 3.x.x: todas las clases pertenecen a la API asincrónica a menos que el nombre de la clase se anexe con Async después de Cosmos.

    • SDK de Java asincrónico 2.x.x: los nombres de clase son similares a Sync Java SDK 2.x.x, pero el nombre comienza con Async.

Estructura jerárquica de API

El SDK de Java de Azure Cosmos DB 4.0 y 3.x.x presentan una estructura jerárquica de API que organiza los clientes, las bases de datos y los contenedores de forma anidada, como se muestra en el siguiente fragmento de código del SDK 4.0:

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

En la versión 2.x.x del SDK de Java de Azure Cosmos DB, todas las operaciones en recursos y documentos se realizan a través de la instancia de cliente.

Representación de documentos

En el SDK de Java 4.0 de Azure Cosmos DB, los POJO personalizados y JsonNodes son las dos opciones para leer y escribir los documentos desde Azure Cosmos DB.

En el SDK de Java de Azure Cosmos DB 3.x.x, la API pública expone el objeto CosmosItemProperties y se utiliza como representación de documento. Esta clase ya no se expone públicamente en la versión 4.0.

Importaciones

  • Los paquetes del SDK de Java 4.0 de Azure Cosmos DB comienzan por com.azure.cosmos

  • Los paquetes 3.x.x.x del SDK de Java de Azure Cosmos DB comienzan por com.azure.data.cosmos

  • Los paquetes de API de Sincronización del SDK de Java 2.x.x de Azure Cosmos DB comienzan por com.microsoft.azure.documentdb

  • El SDK de Java de Azure Cosmos DB 4.0 coloca en un paquete anidado varias clases. Algunos de estos paquetes incluyen:

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • Los análogos de la API asincrónica para todos los paquetes mencionados anteriormente
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode ... etcetera.

Accessors

El SDK de Java de Azure Cosmos DB 4.0 expone get y set métodos para acceder a los miembros de la instancia. Por ejemplo, la CosmosContainer instancia tiene container.getId() métodos y container.setId() .

Esto es diferente del SDK de Java de Azure Cosmos DB 3.x.x, que expone una interfaz fluida. Por ejemplo, una instancia de CosmosSyncContainer tiene container.id() sobrecargada para obtener o establecer el valor id.

Administración de conflictos de dependencias

La actualización del SDK de Java V2 a V4 de Azure Cosmos DB puede introducir conflictos de dependencia debido a cambios en las bibliotecas usadas por el SDK. La resolución de estos conflictos requiere una administración cuidadosa de las dependencias.

  1. Descripción de las nuevas dependencias: el SDK de Azure Cosmos DB V4 tiene su propio conjunto de dependencias que podrían ser diferentes de las de versiones anteriores. Asegúrese de que conoce estas dependencias:

    • 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. Quitar dependencias en conflicto: empiece por quitar las dependencias relacionadas con versiones anteriores del SDK del pom.xml archivo. Entre ellas se incluyen azure-cosmosdb y las dependencias transitivas que el SDK anterior podría haber tenido.

  3. Agregar dependencias del SDK V4: agregue el SDK V4 y sus dependencias a pom.xml. Este es un ejemplo:

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
        <version>4.x.x</version> <!-- Use the latest version available -->
    </dependency>
    
  4. Buscar conflictos de dependencias: use el comando Maven dependency:tree para generar un árbol de dependencias e identificar los conflictos. ¡Corre!

    mvn dependency:tree
    

    Busque las versiones en conflicto de las dependencias. Estos conflictos suelen producirse con bibliotecas como reactor-core, netty-handler, guavay jackson.

  5. Usar administración de dependencias: si encuentra conflictos de versiones, es posible que tenga que invalidar las versiones problemáticas mediante la <dependencyManagement> sección de pom.xml. Este es un ejemplo para aplicar una versión 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. Excluir dependencias transitivas: A veces es posible que necesite excluir dependencias transitivas que sean introducidas por otras dependencias. Por ejemplo, si otra biblioteca incluye una versión anterior de una dependencia que entra en conflicto, puede excluirla de la siguiente manera:

    <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. Recompilar y probar: después de realizar estos cambios, recompile el proyecto y pruébelo exhaustivamente para asegurarse de que las nuevas dependencias funcionan correctamente y que no se producen conflictos en tiempo de ejecución.

Comparaciones de fragmentos de código

Crear recursos

En el fragmento de código siguiente se muestran las diferencias en la forma en que se crean los recursos entre las API asincrónicas 4.0, 3.x.x Async, 2.x.x Sync y 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();

Operaciones de elemento

En el fragmento de código siguiente se muestran las diferencias en cómo se realizan las operaciones de los elementos entre las API 4.0, 3.x.x Async, 2.x.x Sync y 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.

Indexación

En el fragmento de código siguiente se muestran las diferencias en la forma en que se crean los índices entre las API 4.0 Async, 3.x.x Async, 2.x.x Sync y 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);

Procedimientos almacenados

En el fragmento de código siguiente se muestran las diferencias en la forma en que se crean los procedimientos almacenados entre las API Async 4.0, 3.x.x, 2.x.x Sync y 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();

Fuente de cambios

En el siguiente fragmento de código se muestran las diferencias en la ejecución de las operaciones del cambio de feed entre las API asincrónicas 4.0 y 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();

Período de vida(TTL) de nivel de contenedor

En el fragmento de código siguiente se muestran las diferencias en cómo crear tiempo de vida para los datos del contenedor entre las API asincrónicas 4.0, 3.x.x, 2.x.x Sync y 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");

Tiempo de vida a nivel de ítem (TTL)

En el fragmento de código siguiente se muestran las diferencias en cómo crear tiempo de vida para un elemento entre las API asincrónicas 4.0, 3.x.x, 2.x.x Sync y 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
);

Pasos siguientes