1. 概述

本文将带你了解 Azure Cosmos DB 的核心特性,并演示如何通过 Spring Data 与其进行交互。目标是让你在项目中快速集成 Cosmos DB,少踩坑、高效落地。

2. Azure Cosmos DB 简介

Azure Cosmos DB 是微软提供的全球分布式多模型数据库服务,属于典型的 NoSQL 数据库。

它的亮点不是“能用”,而是“稳得一批”——提供对吞吐量、延迟、可用性和一致性四个维度的 SLA 保障。比如,读写操作的可用性承诺高达 **99.999%**(也就是全年宕机不超过 5 分钟),这在云数据库中属于顶级水准。

一致性模型丰富,不玩二元论

很多数据库只提供“强一致”或“最终一致”两种选择,而 Cosmos DB 提供了 5 种一致性级别,让你按需取舍:

✅ 强一致性(Strong)
✅ 有界过期一致性(Bounded Staleness)
✅ 会话一致性(Session)
✅ 一致前缀(Consistent Prefix)
✅ 最终一致性(Eventual)

你可以根据业务场景在性能与一致性之间灵活平衡。

弹性扩展 + 全球分发

  • 存储和吞吐量均可弹性伸缩,按需付费。
  • 支持一键式全球部署,数据可跨 Azure 全球任意区域复制,让终端用户就近访问,降低延迟。
  • 无需管理索引,数据自动索引化。
  • 无固定 Schema,完全 schema-agnostic,适合灵活的数据结构。
  • 支持多种标准 API 接入:SQL、MongoDB、Cassandra、Gremlin、Table 等,迁移成本低。

3. Spring Data Azure Cosmos DB

微软官方提供了 Spring Data 模块,让 Java 开发者可以用熟悉的编程模型操作 Cosmos DB。接下来我们将构建一个 Spring Boot 应用,实现 Product 实体的 CRUD。

⚠️ 提示:本文使用的是较早期的 spring-data-cosmosdb 模块(2.x 版本),基于 Azure SDK for Java 的旧版客户端。新项目建议使用更新的 spring-data-cosmos(基于 Azure SDK v4),但本文仍按原文结构讲解,便于理解演进逻辑。

3.1 使用 Azure Cosmos Emulator 本地开发

不想在 Azure 云上开账号?没问题。微软提供了 Azure Cosmos Emulator,可在本地模拟 Cosmos DB 服务,适合开发和测试。

虽然功能不完全等同于线上服务(比如不支持多区域复制),但基本 CRUD 和分区功能都支持,够用。

我们选择在 Docker for Windows 上运行 Emulator,方便环境隔离。

启动 Emulator 容器

先拉取镜像:

docker pull mcr.microsoft.com/cosmosdb/windows/azure-cosmos-emulator

创建本地挂载目录并启动容器:

md $env:LOCALAPPDATA\CosmosDBEmulator\bind-mount 2>null

docker run --name azure-cosmosdb-emulator --memory 2GB --mount 
"type=bind,source=$env:LOCALAPPDATA\CosmosDBEmulator\bind-mount,destination=C:\CosmosDB.Emulator\bind-mount" 
--interactive --tty -p 8081:8081 -p 8900:8900 -p 8901:8901 -p 8902:8902 -p 10250:10250 
-p 10251:10251 -p 10252:10252 -p 10253:10253 -p 10254:10254 -p 10255:10255 -p 10256:10256 -p 10350:10350 
mcr.microsoft.com/cosmosdb/windows/azure-cosmos-emulator

启动成功后,可通过 https://localhost:8081/_explorer/ 访问 Web 数据管理器。

3.2 配置 Emulator 证书(Java 应用必做)

Emulator 使用自签名证书,Java 应用访问时会因 TLS 验证失败而抛出异常。解决方案是将证书导入 JVM 的信任库(cacerts)。

获取证书

curl -k https://localhost:8081/_explorer/emulator.pem > ~/emulatorcert.crt

导入证书到 keystore

keytool -importcert -alias azure-cosmos-emulator -keystore cacerts -file ~/emulatorcert.crt -storepass changeit

✅ 默认密码是 changeit
✅ 建议将证书导入到项目本地的 keystore,避免污染全局 JVM 环境

4. 在 Spring 中使用 Azure Cosmos DB

4.1 添加依赖并配置连接

pom.xml 中引入 Spring Data Cosmos DB 模块:

<dependency> 
    <groupId>com.microsoft.azure</groupId> 
    <artifactId>spring-data-cosmosdb</artifactId> 
    <version>2.3.0</version> 
</dependency>

application.properties 中配置连接信息:

azure.cosmosdb.uri=https://localhost:8081
azure.cosmosdb.key=C2y6yDjf5/R+ob0N8A7Cgv30VRzGjbvnKtSKV29u4dQd9I4eQqQH9q4aB2v1g==  # Emulator 默认密钥
azure.cosmosdb.secondaryKey=RolloverKey==  # 可选
azure.cosmosdb.database=product-db

🔐 注意:生产环境务必通过 Azure Key Vault 管理密钥,不要硬编码

配置类:启用 Cosmos DB 支持

创建配置类,继承 AbstractCosmosConfiguration,并使用 @EnableCosmosRepositories 扫描仓库接口:

@Configuration
@EnableCosmosRepositories(basePackages = "com.example.repository")
public class AzureCosmosDbConfiguration extends AbstractCosmosConfiguration {

    @Value("${azure.cosmosdb.uri}")
    private String uri;

    @Value("${azure.cosmosdb.key}")
    private String key;

    @Value("${azure.cosmosdb.database}")
    private String dbName;

    private CosmosKeyCredential cosmosKeyCredential;

    @Bean
    public CosmosDBConfig getConfig() {
        this.cosmosKeyCredential = new CosmosKeyCredential(key);
        CosmosDBConfig cosmosdbConfig = CosmosDBConfig.builder(uri, this.cosmosKeyCredential, dbName)
            .build();
        return cosmosdbConfig;
    }
}

CosmosKeyCredential 支持密钥轮换,推荐使用
basePackages 指定仓库接口所在包路径

4.2 定义实体类

使用 @Document 注解标记实体,映射到 Cosmos DB 的容器(Container):

@Document(collection = "products")
public class Product {

    @Id
    private String productid;

    private String productName;

    private double price;

    @PartitionKey
    private String productCategory;

    // 标准 getter / setter 省略
}

关键点说明:

注解 说明
@Document(collection = "products") 指定容器名为 products,若不指定则默认使用类名
@Id 标记文档主键字段,对应 Cosmos DB 的 _id
@PartitionKey 指定分区键,用于水平扩展和查询优化

⚠️ 分区键一旦设定,不可更改,选型需谨慎

你还可以通过 @DocumentIndexingPolicy 自定义索引策略,或添加 @Version 注解配合 _etag 字段实现乐观锁。

4.3 定义 Repository 接口

创建仓库接口,继承 CosmosRepository,即可获得开箱即用的 CRUD 方法:

@Repository
public interface ProductRepository extends CosmosRepository<Product, String> {

    List<Product> findByProductName(String productName);

}
  • Product:实体类型
  • String:主键类型(即 @Id 字段类型)
  • findByProductName:Spring Data 自动解析方法名生成查询,无需手动写 SQL

4.4 编写测试验证连接

使用 @SpringBootTest 测试实体的保存与查询:

@SpringBootTest
public class AzureCosmosDbApplicationManualTest {

    @Autowired
    private ProductRepository productRepository;

    @Test
    public void givenProductIsCreated_whenCallFindById_thenProductIsFound() {
        Product product = new Product();
        product.setProductid("1001");
        product.setProductCategory("Shirt");
        product.setPrice(110.0);
        product.setProductName("Blue Shirt");

        productRepository.save(product);

        Product retrievedProduct = productRepository.findById("1001", new PartitionKey("Shirt"))
            .orElse(null);

        Assert.notNull(retrievedProduct, "Retrieved Product is Null");
    }
}

✅ 注意:查询时必须传入 PartitionKey,否则会触发跨分区查询(性能差且消耗更多 RU) ✅ 测试通过说明:本地 Emulator + Spring Data 集成成功

5. 总结

本文带你完成了 Spring Boot 与 Azure Cosmos DB 的基础集成,涵盖:

  • ✅ 使用 Emulator 本地开发
  • ✅ 证书配置避坑
  • ✅ 实体映射与分区键设计
  • ✅ 仓库接口定义与自动查询生成
  • ✅ 基础 CRUD 测试验证

虽然示例使用的是旧版 SDK,但核心思想(如注解驱动、Repository 模式、分区键使用)在新版 spring-data-cosmos 中依然适用。建议新项目直接使用官方推荐的最新模块,API 更现代,性能更好。

完整代码示例可参考:GitHub - persistence-modules/spring-data-cosmosdb


原始标题:Introduction to Spring Data Azure Cosmos DB