You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Azure Cosmos DB Java SDK v4异步API的CosmosItemResponse中获取文档的_ts值

在Azure Cosmos DB Java SDK v4异步API中获取文档的_ts时间戳

我完全懂你的困扰——在v2 SDK里可以通过azure.documentdb.document.getResource()轻松拿到文档的_ts值,甚至还能从响应头里直接取,但到了v4异步API的CosmosItemResponse里,好像找不到直接对应的方法,而且你尝试的x-ms-last-state-change-utc确实不是文档更新后的_ts(那个是账户级别的状态变更时间,和文档本身完全无关)。

下面给你两种靠谱的解决方案,都是针对Java SDK v4异步场景的:

方法1:在实体类中映射_ts字段(推荐)

v4 SDK更偏向强类型实体操作,你可以直接在Person类里添加一个字段,用Jackson注解映射Cosmos DB的_ts系统属性:

import com.fasterxml.jackson.annotation.JsonProperty;

public class Person {
    // 你的现有字段:id、personId、eTag等
    private long ts;

    // 映射Cosmos DB的_ts属性
    @JsonProperty("_ts")
    public long getTs() {
        return ts;
    }

    @JsonProperty("_ts")
    public void setTs(long ts) {
        this.ts = ts;
    }

    // 其他字段的getter/setter
}

这样不管是readItem还是replaceItem返回的CosmosItemResponse<Person>,你都可以直接从getItem()拿到的Person对象里调用getTs()获取_ts值(注意_ts是Unix时间戳,单位为秒,需要转成毫秒的话乘以1000即可)。

方法2:从响应头获取x-ms-item-ts字段

如果你不想修改实体类,也可以直接从CosmosItemResponse的响应头里提取x-ms-item-ts,这个字段就是文档_ts的字符串形式:

// 在replaceItem的响应处理中
responsePersonReplaced = repalcedFlux.log().flatMap(x -> {
    String tsHeader = x.getResponseHeaders().get("x-ms-item-ts");
    if (tsHeader != null) {
        // 转成毫秒时间戳返回
        return Mono.just(Long.parseLong(tsHeader) * 1000L);
    } else {
        return Mono.empty();
    }
}).block();

优化后的示例代码

结合方法1,我把你的updatePerson方法重构得更简洁直观,同时修正了返回类型(时间戳用long比double更合理):

public long updatePerson(Person p) {
    // 读取现有文档,获取最新eTag和_ts
    Person existingPerson = container.readItem(p.getId(), new PartitionKey(p.getPersonId()), Person.class)
            .log()
            .map(CosmosItemResponse::getItem)
            .block();

    if (existingPerson == null) {
        logger.error("待更新的Person文档不存在,ID: {}", p.getId());
        return -1;
    }

    // 设置匹配的eTag,确保乐观并发控制
    p.seteTag(existingPerson.geteTag());
    CosmosItemRequestOptions options = new CosmosItemRequestOptions();
    options.setIfMatchETag(existingPerson.geteTag());

    try {
        // 执行替换并返回更新后的_ts(转成毫秒)
        return container.replaceItem(p, p.getId(), new PartitionKey(p.getPersonId()), options)
                .log()
                .map(response -> response.getItem().getTs() * 1000L)
                .block();
    } catch (Exception e) {
        logger.error("更新Person文档失败: {}", e.getLocalizedMessage());
        return -1;
    }
}

补充说明

v4 SDK移除了v2里的getResource()方法,是因为设计理念转向了更直接的实体映射,但系统属性(_ts、_etag、_self等)依然可以通过上述两种方式获取,其中实体类映射的方式更符合v4的使用习惯,也更易于维护。

内容的提问来源于stack exchange,提问作者sourav agrawal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:18:13