Перевод приложения на использование пакета средств разработки Java для Azure Cosmos DB версии 4

ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL

Внимание

Дополнительные сведения об этом пакете SDK см. в заметках о выпуске пакета SDK Java Azure Cosmos DB версии 4, репозитории Maven, рекомендациях по повышению производительности для пакета SDK Java Azure Cosmos DB версии 4, а также в руководстве по устранению неполадок для пакета SDK Java Azure Cosmos DB версии 4.

Внимание

Поскольку пакет SDK Azure Cosmos DB для Java версии 4 позволяет улучшить пропускную способность на 20 %, предоставляет прямой режим на основе TCP и поддержку новейших функций серверной службы, мы рекомендуем выполнить обновление до версии 4 при следующей возможности. Продолжайте читать, чтобы узнать больше.

Выполните обновление до Azure Cosmos DB с последней версией пакета SDK для Java, чтобы получить максимум от возможностей Azure Cosmos DB — конкурентоспособной управляемой службы нереляционных баз данных, доступности на уровне 99,999 %, возможности уникального управления ресурсами и многого другого. В этой статье объясняется, как обновить существующее приложение Java, которое использует более старый пакет SDK Java для Azure Cosmos DB до более нового пакета SDK Java для Azure Cosmos DB версии 4.0 для API для NoSQL. Пакет средств разработки Java для Azure Cosmos DB версии 4 соответствует пакету com.azure.cosmos. Инструкции из этого документа можно использовать при переводе приложения с любого из следующих пакетов средств разработки Java для Azure Cosmos DB:

  • пакет средств разработки Sync Java версии 2.x.x;
  • пакет средств разработки Async Java версии 2.x.x;
  • пакет средств разработки Java версии 3.x.x.

Сопоставления пакета средств разработки Java для Azure Cosmos DB и пакетов

В следующей таблице перечислены разные пакеты средств разработки Java для Azure Cosmos DB, имена пакетов и сведения о выпуске.

пакет SDK для Java Дата выпуска Пакетные API-интерфейсы JAR-файл Maven Имя пакета Java Справочник по API Заметки о выпуске Дата прекращения поддержки
Async 2.x.x 2018 июня Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Заметки о выпуске 31 августа 2024 г.
Sync 2.x.x Сентябрь 2018 г. Sync com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 29 февраля 2024 г.
3.x.x Июль 2019 г. Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 31 августа 2024 г.
4.0 Июнь 2020 г. Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

Изменения реализации на уровне пакета SDK

Ниже приведены основные различия в реализации между разными пакетами SDK.

RxJava заменяется на Reactor в пакетах средств разработки Java для Azure Cosmos DB версий 3.x.x и 4.0

Если вы еще не знакомы с асинхронным и (или) реактивным программированием, изучите руководство по шаблону реактора, в котором приведены общие сведения об асинхронном программировании и проекте Reactor. Это руководство может оказаться полезным, если вы ранее использовали пакет средств разработки Sync Java для Azure Cosmos DB версии 2.x.x или пакет средств разработки Sync Java для Azure Cosmos DB версии 3.x.x.

Если вы используете пакет средств разработки Async Java для Azure Cosmos DB версии 2.x.x и планируете перейти на пакет SDK 4.0, ознакомьтесь со статьей Сравнительная характеристика Reactor и RxJava, где представлены инструкции по преобразованию кода для RxJava в код для Reactor.

Пакет средств разработки Java для Azure Cosmos DB версии 4 имеет режим прямого подключения к API-интерфейсам Sync и Async.

Если вы используете пакет средств разработки Sync Java для Azure Cosmos DB версии 2.x.x, обратите внимание, что режим прямого подключения по протоколу TCP (а не HTTP) реализован в пакете средств разработки Java для Azure Cosmos DB версии 4.0 для API-интерфейсов Async и Sync.

Изменения на уровне API

Ниже перечислены изменения на уровне API в пакете средств разработки Java для Azure Cosmos DB версии 4.x.x по сравнению с предыдущими пакетами SDK (Java SDK 3.x.x, Async Java SDK 2.x.x и Sync Java SDK 2.x.x):

Соглашение об именовании в пакете SDK Azure Cosmos DB Java

  • Пакеты средств разработки Java для Azure Cosmos DB версий 3.x.x и 4.0 указывают ресурсы клиента как Cosmos<resourceName>. Например CosmosClient, CosmosDatabase, CosmosContainer. В то же время пакет средств разработки Java для Azure Cosmos DB версии 2.x.x не имеет единообразной схемы именования.

  • Пакеты средств разработки Java для Azure Cosmos DB версий 3.x.x и 4.0 предоставляют API-интерфейсы Sync и Async.

    • Java SDK 4.0. Все классы принадлежат API Sync, если имя класса не имеет постфикса Async после Cosmos.

    • Java SDK 3.x.x. Все классы принадлежат API Async, если имя класса не имеет постфикса Async после Cosmos.

    • Async Java SDK 2.x.x. Имена классов похожи на имена в пакете средств разработки Java версии 2.x.x, но всегда начинаются с префикса Async.

Иерархическая структура API

Пакеты средств разработки Java для Azure Cosmos DB версий 4.0 и 3.x.x представляют иерархическую структуру API, которая поддерживает вложенность клиентов, баз данных и контейнеров, как показано в следующем фрагменте кода для пакета средств разработки версии 4.0:

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

В пакете средств разработки Java для Azure Cosmos DB версии 2.x.x все операции с ресурсами и документами выполняются через экземпляр клиента.

Представление документов

В пакете средств разработки Java для Azure Cosmos DB версии 4.0 есть два варианта для чтения и записи документов из Azure Cosmos DB — пользовательские POJO и JsonNodes.

В пакете средств разработки Java для Azure Cosmos DB версии 3.x.x объект CosmosItemProperties предоставляется через общедоступные API-интерфейсы в формате представления документа. Этот класс больше не является общедоступным в версии 4.0.

Импорт

  • Все пакеты средств разработки Java для Azure Cosmos DB версии 4.0 начинаются с инструкций com.azure.cosmos

  • Пакеты средств разработки Java для Azure Cosmos DB версии 3.x.x начинаются с инструкций com.azure.data.cosmos

  • Пакеты Sync API-интерфейсов SDK для Java версии 2.x.x в Azure Cosmos DB начинаются с com.microsoft.azure.documentdb

  • Пакет средств разработки Java для Azure Cosmos DB версии 4.0 размещает несколько классов во вложенном пакете com.azure.cosmos.models. Сюда относятся следующие пакеты.

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • Аналоги API Async для всех перечисленных выше пакетов:
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode... и т. д.

Методы доступа

Пакет средств разработки Java для Azure Cosmos DB версии 4.0 предоставляет методы get и set для доступа к членам экземпляра. Например, экземпляр CosmosContainer содержит методы container.getId() и container.setId().

В отличие от него, пакет средств разработки Java для Azure Cosmos DB версии 3.x.x предоставляет текучий интерфейс. Например, экземпляр CosmosSyncContainer имеет container.id() с перегрузками для получения или установки значения id.

Управление конфликтами зависимостей

Обновление пакета SDK Java для Azure Cosmos DB версии 2 до версии 4 может привести к конфликтам зависимостей из-за изменений библиотек, используемых пакетом SDK. Для устранения этих конфликтов требуется тщательное управление зависимостями.

  1. Общие сведения о новых зависимостях: пакет SDK для Azure Cosmos DB версии 4 имеет собственный набор зависимостей, которые могут отличаться от зависимостей в предыдущих версиях. Убедитесь, что вы знаете об этих зависимостях:

    • 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. Удалите конфликтующие зависимости: начните с удаления зависимостей, связанных с предыдущими версиями пакета SDK из файла pom.xml . К ним относятся azure-cosmosdb и все транзитивные зависимости, которые, возможно, имели старый пакет SDK.

  3. Добавьте зависимости пакета SDK версии 4: добавьте пакет SDK версии 4 и его зависимости в вашу pom.xml. Приведем пример:

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-cosmos</artifactId>
        <version>4.x.x</version> <!-- Use the latest version available -->
    </dependency>
    
  4. Проверьте наличие конфликтов зависимостей: используйте команду Maven dependency:tree для создания дерева зависимостей и выявления конфликтов. Запустить:

    mvn dependency:tree
    

    Найдите конфликтующие версии зависимостей. Эти конфликты часто возникают с такими библиотеками, как reactor-core, netty-handlerguavaи jackson.

  5. Используйте управление зависимостями. Если возникают конфликты версий, может потребоваться переопределить проблемные версии, используя <dependencyManagement> раздел в вашем pom.xml. Ниже приведен пример применения определенной версии 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. Исключить транзитивные зависимости. Иногда может потребоваться исключить транзитивные зависимости, вызванные другими зависимостями. Например, если другая библиотека приносит более старую версию зависимости, которая конфликтует, можно исключить следующее:

    <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. Перестроение и тестирование. После внесения этих изменений перестройте проект и тщательно протестируйте его, чтобы обеспечить правильную работу новых зависимостей и отсутствие конфликтов среды выполнения.

Сравнение фрагментов кода

Создание ресурсов

В следующем фрагменте кода показаны различия в создании ресурсов между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 2.x.x.


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

Операции с элементами

В следующем фрагменте кода показаны различия в выполнении операций с элементами между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 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.

Индексирование

В следующем фрагменте кода показаны различия в индексировании между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 2.x.x.


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

Хранимые процедуры

В следующем фрагменте кода показаны различия в создании хранимых процедур между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 2.x.x.


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

Канал изменений

В следующем фрагменте кода показаны различия между выполнением операций с каналом изменений между API-интерфейсами Async версий 4.0 и 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.elastic())
        .subscribe();

Срок жизни на уровне контейнера

В следующем фрагменте кода показаны различия при создании срока жизни данных в контейнере между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 2.x.x.


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

Срок жизни на уровне элемента

В следующем фрагменте кода показаны различия при создании срока жизни для элемента между API Async версий 4.0, 3.x.x и 2.x.x и API Sync версий 2.x.x.


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

Следующие шаги