Поделиться через


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

Это важно

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

Это важно

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

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

  • Синхронизация пакета SDK java 2.x.x
  • Async Java SDK 2.x.x
  • Пакет SDK для Java 3.x.x

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

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

пакет SDK для Java Дата выпуска Объединенные API Maven Jar Имя пакета Java Справочник по API Заметки о релизе Дата завершения использования
Async 2.x.x 2018 июня Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API Заметки о выпуске 31 августа 2024 г.
Синхронизация 2.x.x Сентябрь 2018 г. Синхронизация 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 SDK для Azure Cosmos DB версий 3.x.x и 4.0

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

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

Пакет SDK Java для Azure Cosmos DB версии 4 поддерживает режим прямого соединения как в Асинхронных API, так и в Синхронных API.

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

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

Ниже приведены изменения на уровне API в Azure Cosmos DB Java SDK 4.x.x в сравнении с предыдущими версиями Java SDK (Java SDK 3.x.x, Асинхронный Java SDK 2.x.x и Синхронный Java SDK 2.x.x):

Соглашения об именовании Java SDK для Azure Cosmos DB

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

  • Пакет SDK Java для Azure Cosmos DB 3.x.x и 4.0 предлагает синхронные и асинхронные API.

    • Пакет SDK для Java 4.0 : все классы относятся к API синхронизации, если только имя класса не добавляется после AsyncCosmos.

    • Пакет SDK для Java 3.x.x. Все классы принадлежат API Async, если только имя класса не добавляется после AsyncCosmos.

    • Async Java SDK 2.x.x: Имена классов аналогичны Sync Java SDK 2.x.x, однако имя начинается с Async.

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

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

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

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

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

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

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

Импорты

  • Пакеты Java SDK для Azure Cosmos DB 4.0 начинаются с com.azure.cosmos

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

  • Пакеты синхронизации API Azure Cosmos DB Java SDK 2.x.x начинаются с com.microsoft.azure.documentdb

  • Пакет SDK Java для Azure Cosmos DB 4.0 помещает несколько классов в вложенный пакет com.azure.cosmos.models. Некоторые из этих пакетов включают:

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

Accessors

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

Это отличается от пакета SDK 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 4.0, 3.x.x Async, 2.x.x Sync и 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();

Манипуляции с элементами

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


// 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 4.0, 3.x.x Async, 2.x.x Sync и 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);

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

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


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

Время жизни на уровне контейнера (TTL)

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

Время жизни элемента (TTL)

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


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

Дальнейшие шаги