다음을 통해 공유


Azure Cosmos DB Java SDK v4를 사용하도록 애플리케이션 마이그레이션

적용 대상: NoSQL

Important

이 SDK에 대한 자세한 내용은 Azure Cosmos DB Java SDK v4 릴리스 정보, Maven 리포지토리, Azure Cosmos DB Java SDK v4 성능 팁 및 Azure Cosmos DB Java SDK v4 문제 해결 가이드를 참조하세요.

Important

Azure Cosmos DB Java SDK v4는 최대 20% 향상된 처리량, TCP 기반 직접 모드 및 최신 백엔드 서비스 기능을 지원하므로 다음 기회에 v4로 업그레이드하는 것이 좋습니다. 자세히 알아보려면 계속 읽어보세요.

최신 Azure Cosmos DB Java SDK로 업데이트하여 Azure Cosmos DB가 제공해야 하는 서비스로서, 경쟁력 있는 성능, 고가용성, 일종의 리소스 거버넌스 등을 제공하는 관리형 비관계형 데이터베이스 서비스를 최대한 활용합니다. 이 문서에서는 이전 Azure Cosmos DB Java SDK를 사용하는 기존 Java 애플리케이션을 최신 API for NoSQL용 Azure Cosmos DB Java SDK 4.0으로 업그레이드하는 방법을 설명합니다. Azure Cosmos DB Java SDK v4는 com.azure.cosmos 패키지에 해당합니다. 다음 Azure Cosmos DB Java SDK 중 하나에서 애플리케이션을 마이그레이션하는 경우 이 문서의 지침을 사용할 수 있습니다.

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

Azure Cosmos DB Java SDK와 패키지 매핑

다음 표에는 다양한 Azure Cosmos DB Java SDK, 패키지 이름 및 릴리스 정보가 나와 있습니다.

Java SDK 릴리스 날짜 번들 API Maven Jar Java 패키지 이름 API 참조 릴리스 정보 만료 날짜
Async 2.x.x 2018년 6월 Async(RxJava) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API 릴리스 정보 2024년 8월 31일 토요일
Sync 2.x.x 2018년 9월 동기화 com.microsoft.azure::azure-documentdb com.microsoft.azure.cosmosdb API 2024년 2월 29일 목요일
3.x.x 2019년 7월 Async(Reactor)/Sync com.microsoft.azure::azure-cosmos com.azure.data.cosmos API - 2024년 8월 31일 토요일
4.0 2020년 6월 Async(Reactor)/Sync com.azure::azure-cosmos com.azure.cosmos API - -

SDK 수준 구현 변경 내용

다음은 서로 다른 SDK의 주요 구현 차이점입니다.

RxJava는 Azure Cosmos DB Java SDK 버전 3.x.x 및 4.0에서 Reactor로 바뀝니다.

비동기 프로그래밍 또는 사후 프로그래밍에 익숙하지 않은 경우 비동기 프로그래밍 및 Project Reactor를 소개하는 Reactor 패턴 가이드를 참조하세요. 이 가이드는 이전의 Azure Cosmos DB Sync Java SDK 2.x.x 또는 Azure Cosmos DB Java SDK 3.x.x Sync API를 사용하고 있는 경우 유용할 수 있습니다.

Azure Cosmos DB Async Java SDK 2.x.x를 사용하고 있고 4.0 SDK로 마이그레이션할 계획인 경우 Reactor를 사용하도록 RxJava 코드를 변환하는 방법에 대한 지침은 Reactor 및 RxJava 가이드를 참조하세요.

Azure Cosmos DB Java SDK v4에는 Async 및 Sync API의 직접 연결 모드가 있습니다.

Azure Cosmos DB Sync Java SDK 2.x.x를 사용하고 있는 경우 TCP(HTTP 아님) 기반 직접 연결 모드가 Async 및 Sync API를 위해 Azure Cosmos DB Java SDK 4.0에서 구현됩니다.

API 수준 변경

다음은 이전 SDK(Java SDK 3.x.x, Async Java SDK 2.x.x 및 Sync Java SDK 2.x.x)와 비교하여 Azure Cosmos DB Java SDK 4.x.x에 있는 API 수준의 변경 내용입니다.

Azure Cosmos DB Java SDK 명명 규칙

  • Azure Cosmos DB Java SDK 3.x.x 및 4.0은 클라이언트 리소스를 Cosmos<resourceName>으로 참조합니다. 예: CosmosClient, CosmosDatabase, CosmosContainer. 버전 2.x.x에서는 Azure Cosmos DB Java SDK에 일정한 명명 체계가 없습니다.

  • Azure Cosmos DB Java SDK 3.x.x 및 4.0은 Sync 및 Async API를 모두 제공합니다.

    • Java SDK 4.0 : 클래스 이름이 Cosmos 뒤에 Async가 추가되어 있지 않으면 모든 클래스가 Sync API에 포함됩니다.

    • Java SDK 3.x.x: 클래스 이름이 Cosmos 뒤에 Async가 추가되어 있지 않으면 모든 클래스가 Async API에 포함됩니다.

    • Async Java SDK 2.x.x: 클래스 이름은 Sync Java SDK 2.x.x와 유사하지만 이름이 Async로 시작합니다.

계층적 API 구조

Azure Cosmos DB Java SDK 4.0 및 3.x.x에는 다음 4.0 SDK 코드 조각에 표시된 대로 클라이언트, 데이터베이스 및 컨테이너를 중첩된 방식으로 구성하는 계층적 API 구조가 도입되었습니다.

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

Azure Cosmos DB Java SDK 버전 2.x.x에서 리소스 및 문서에 대한 모든 작업은 클라이언트 인스턴스를 통해 수행됩니다.

문서 표현

Azure Cosmos DB Java SDK 4.0에서 사용자 지정 POJO 및 JsonNodes는 Azure Cosmos DB에서 문서를 읽고 쓰는 두 가지 옵션입니다.

Azure Cosmos DB Java SDK 3.x.x에서 CosmosItemProperties 개체는 공개 API에 의해 노출되고 문서 표현으로 제공됩니다. 이 클래스는 더 이상 버전 4.0에서 공개적으로 노출되지 않습니다.

가져오기

  • Azure Cosmos DB Java SDK 4.0 패키지는 com.azure.cosmos로 시작합니다.

  • Azure Cosmos DB Java SDK 3.x.x 패키지는 com.azure.data.cosmos로 시작합니다.

  • Azure Cosmos DB Java SDK 2.x.x Sync API packages는 com.microsoft.azure.documentdb로 시작합니다.

  • Azure Cosmos DB Java SDK 4.0은 여러 클래스를 중첩 패키지 com.azure.cosmos.models에 배치합니다. 이러한 패키지 중 일부는 다음과 같습니다.

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • 위의 모든 패키지에 대해 유사한 Async API
    • CosmosContainerProperties
    • FeedOptions
    • PartitionKey
    • IndexingPolicy
    • IndexingMode

접근자

Azure Cosmos DB Java SDK 4.0은 getset 메서드를 노출하여 인스턴스 멤버에 액세스합니다. 예를 들어 CosmosContainer 인스턴스에는 container.getId()container.setId() 메서드가 있습니다.

이는 흐름 인터페이스를 노출하는 Azure Cosmos DB Java SDK 3.x.x와 다릅니다. 예를 들어 CosmosSyncContainer 인스턴스에는 id 값을 가져오거나 설정하기 위해 오버로드된 container.id()가 있습니다.

종속성 충돌 관리

Azure Cosmos DB Java SDK V2에서 V4로 업그레이드하면 SDK에서 사용하는 라이브러리의 변경으로 인해 종속성 충돌이 발생할 수 있습니다. 이러한 충돌을 해결하려면 종속성을 신중하게 관리해야 합니다.

  1. 새로운 종속성 이해: Azure Cosmos DB V4 SDK에는 이전 버전과 다른 고유한 종속성 집합이 있습니다. 다음과 같은 종속성을 알고 있는지 확인합니다.

    • 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. 충돌하는 종속성 제거: pom.xml 파일에서 이전 버전의 SDK와 관련된 종속성을 제거하는 것부터 시작합니다. 여기에는 azure-cosmosdb 및 이전 SDK에 있었을 수 있는 모든 전이적 종속성이 포함됩니다.

  3. V4 SDK 종속성 추가: pom.xml에 V4 SDK 및 종속성을 추가합니다. 예를 들어 다음과 같습니다.

    <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-handler, guava, jackson과 같은 라이브러리에서 자주 발생합니다.

  5. 종속성 관리 사용: 버전 충돌이 발생하는 경우 pom.xml<dependencyManagement> 섹션을 사용하여 문제가 있는 버전을 재정의해야 할 수도 있습니다. 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. 다시 빌드 및 테스트: 이러한 변경을 한 후에는 프로젝트를 다시 빌드하고 철저히 테스트하여 새로운 종속성이 올바르게 작동하고 런타임 충돌이 발생하지 않는지 확인합니다.

코드 조각 비교

리소스 만들기

다음 코드 조각은 4.0, 3.x.x Async, 2.x.x Sync, 2.x.x Async API 간에 리소스를 만드는 방법의 차이점을 보여 줍니다.


// 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 Async, 2.x.x Sync, 2.x.x Async 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.

인덱싱

다음 코드 조각은 4.0, 3.x.x Async, 2.x.x Sync, 2.x.x Async API 간에 인덱싱을 만드는 방법의 차이점을 보여 줍니다.


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

변경 피드

다음 코드 조각은 4.0과 3.x.x Async API에서 변경 피드 작업을 실행하는 방법의 차이점을 보여 줍니다.


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

컨테이너 수준 TTL(Time-To-Live)

다음 코드 조각은 4.0, 3.x.x Async, 2.x.x Sync, 2.x.x Async API 간에 컨테이너에서 데이터의 TTL(Time to Live)을 만드는 방법의 차이점을 보여 줍니다.


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(Time-To-Live)

다음 코드 조각은 4.0, 3.x.x Async, 2.x.x Sync, 2.x.x Async API 간에 항목의 TTL(Time to Live)을 만드는 방법의 차이점을 보여 줍니다.


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

다음 단계