分享方式:


遷移您的應用程式,以使用 Azure Cosmos DB Java SDK v4

適用於:NoSQL

重要

如需此 SDK 的詳細資訊,請檢視 Azure Cosmos DB Java SDK v4 版本資訊Maven 存放庫、Azure Cosmos DB Java SDK v4 效能秘訣和 Azure Cosmos DB Java SDK v4 疑難排解指南

重要

由於 Azure Cosmos DB Java SDK v4 具有提升高達 20% 的輸送量、以 TCP 為基礎的直接模式,以及最新後端服務功能的支援,因此建議您在下次有機會時升級至 v4。 若要深入了解,請繼續閱讀以下內容。

更新至最新的 Azure Cosmos DB Java SDK,以充分利用 Azure Cosmos DB 所提供的功能 - 這是一項受控的非關聯式資料庫服務,提供具競爭力的效能、99.999% 的可用性、獨一無二的資源管理及更多功能。 本文說明如何將使用舊版 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 移轉應用程式,您可以使用本文件中的指示:

  • 同步 Java SDK 2.x.x
  • 非同步 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 參考 版本資訊 淘汰日期
非同步 2.x.x 2018 年 6 月 非同步 (RxJAVA) com.microsoft.azure::azure-cosmosdb com.microsoft.azure.cosmosdb.rx API 版本資訊 2024 年 8 月 31 日
同步 2.x.x 2018 年 9 月 Sync 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

如果您不熟悉非同步程式設計或回應式程式設計,請參閱 Reactor 模式指南,以取得非同步程式設計和專案 Reactor 的簡介。 如果您一直在使用 Azure Cosmos DB 同步 JAVA SDK 2.x.x 或 Azure Cosmos DB JAVA SDK 3.x.x 同步 API,本指南可能會很有用。

如果您一直在使用 Azure Cosmos DB 非同步 JAVA SDK 2.x.x,並打算移轉至 4.0 SDK,請參閱 Reactor vs RxJAVA 指南,以取得將 RxJAVA 程式碼轉換為使用 Reactor 的指引。

Azure Cosmos DB JAVA SDK v4 在非同步和同步 API 中都有直接連線模式

如果您已使用 Azure Cosmos DB 同步 JAVA SDK 2.x.x,請注意以 TCP 為基礎的直接連線模式 (相對於 HTTP),會在適用於非同步和同步 API 的 Azure Cosmos DB JAVA SDK 4.0 中執行。

API 層級變更

相較於先前的 SDK,以下是 Azure Cosmos DB JAVA SDK 4.x 中的 API 層級變更 (JAVA SDK 3.x.x、Async JAVA SDK 2.x.x 和 Sync JAVA SDK 2.x.x):

Azure Cosmos DB JAVA SDK 命名慣例

  • Azure Cosmos DB JAVA SDK 3.x.x 和4.0 會將用戶端資源稱為 Cosmos<resourceName>。 例如,CosmosClientCosmosDatabaseCosmosContainer。 而在2.x.x 版中,Azure Cosmos DB JAVA SDK 並沒有統一的命名配置。

  • Azure Cosmos DB JAVA SDK 3.x.x 和4.0 提供同步和非同步 API。

    • Java SDK 4.0:所有類別都屬於同步 API,除非類別名稱在 Cosmos 之後附加 Async

    • Java SDK 3.x.x:所有類別都屬於非同步 API,除非類別名稱在 Cosmos 之後附加 Async

    • Async Java SDK 2.x.x:類別名稱類似於同步 Java SDK 2.x.x,但名稱開頭為 Async

階層式 API 結構

Azure Cosmos DB JAVA SDK 4.0 和 3.x.x 引進階層式 API 結構,以嵌套的方式組織用戶端、資料庫和容器,如下列 4.0 SDK 程式碼片段所示:

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

在2.x.x 版的 Azure Cosmos DB JAVA SDK 中,資源和文件上的所有作業都是透過用戶端執行個體執行。

代表文件

在 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 同步 API 套件開頭為 com.microsoft.azure.documentdb

  • Azure Cosmos DB JAVA SDK 4.0 會將數個類別放在嵌套封裝 com.azure.cosmos.models中。 這些封裝有些包括:

    • CosmosContainerResponse
    • CosmosDatabaseResponse
    • CosmosItemResponse
    • 所有上述封裝的非同步 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 執行個體具有多載的 container.id(),以取得或設定 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 相依性:將 V4 SDK 及其相依性新增至您的 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-corenetty-handlerguavajackson

  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 非同步、2.x.x 同步和 2.x.x 非同步 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 非同步、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.

編製索引

下列程式碼片段顯示 4.0、3.x.x 非同步、2.x.x 同步和 2.x.x 非同步 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 非同步、2.x.x 同步和 2.x.x 非同步 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 非同步 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)

下列程式碼片段顯示 4.0、3.x.x 非同步、2.x.x 同步和 2.x.x 非同步 API 在如何為容器中的資料建立存留時間方面有何差異:


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)

下列程式碼片段顯示 4.0、3.x.x 非同步、2.x.x 同步和 2.x.x 非同步 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
);

下一步