你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
适用于 Java 的 Azure Spring Data Cosmos 客户端库 - 版本 5.6.0
Azure Spring Data Cosmos 基于 Spring Data 框架,使用 SQL API 向 Azure Cosmos DB 提供 Spring Data 支持。 Azure Cosmos DB 是一种全球分布式数据库服务,它允许开发人员使用各种标准 API(如 SQL、MongoDB、Cassandra、Graph 和表)处理数据。
Spring Boot 支持策略
此项目支持多个 Spring Boot 版本。 有关当前受支持版本的完整列表,请访问 Spring 版本映射。
当 Spring Boot 版本不再受支持或不再以任何形式发布时,它们将标记为“生命周期结束”。 如果你运行的是 EOL 版本,应尽快升级。
请注意,在标记为“生命周期结束”之前,某个版本可能不再受支持。 在此期间,你应仅预期针对严重 bug 或安全问题发布。
有关受支持的 Spring Boot 版本的详细信息,请访问受支持的 Spring Boot 版本。
Spring Boot 版本支持
Maven 用户可从 spring-boot-starter-parent
项目继承来获取依赖项管理部分,使 Spring 能够管理依赖项的版本。
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
</parent>
通过该设置,你还可通过替代你自己的项目中的属性,来替代单个依赖项。 例如,若要升级到其他 Spring Data 版本训练,你要在 pom.xml 中添加以下内容。
<properties>
<spring-data-releasetrain.version>${spring.data.version}</spring-data-releasetrain.version>
</properties>
如果你不想使用 spring-boot-starter-parent
,那么你可使用 scope=import
依赖项来继续享有依赖项管理的好处:
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
应使用哪个版本的 Azure Spring Data Cosmos
从 Spring Boot / Spring Cloud 版本映射到 Azure Spring Data Cosmos 版本
Spring Boot 版本 | Spring Cloud 版本 | Azure Spring Data Cosmos 版本 |
---|---|---|
3.0.x | 2022.0.x | 5.3.0 及更高版本 |
2.7.x | 2021.0.x | 3.23.0 及更高版本 |
2.6.x | 2021.0.x | 3.15.0 - 3.22.0 |
2.5.x | 2020.0.x | 3.8.0 - 3.14.0 |
2.4.x | 2020.0.x | 3.5.0 - 3.7.0 |
我使用的是 Spring Boot 版本 X
如果在项目中使用 Spring Boot ,可以在上表中找到相关的 Azure Spring Data Cosmos 版本。 例如:如果使用 Spring Boot 3.0.x,则应使用 Azure Spring Data Cosmos 5.3.0 及更高版本。
我使用的是 Spring Cloud 版本 Y
如果在项目中使用 Spring Cloud ,还可以在上表中找到相关的 Azure Spring Data Cosmos 版本。 例如,如果使用 Spring Cloud 2022.0.x,则应使用 Azure Spring Data Cosmos 版本 5.3.0 及更高版本。
Spring Data 版本支持
此项目支持 spring-data-commons 3.0.x
版本。
上述设置不允许使用上述属性替代单个依赖项。 若要获得相同的结果,需要在项目的 dependencyManagement 中的 spring-boot-dependencies
条目前面添加一个条目。 例如,若要升级到其他 Spring Data 版本训练,你要在 pom.xml 中添加以下内容。
<dependencyManagement>
<dependencies>
<!-- Override Spring Data release train provided by Spring Boot -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>${spring.data.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
注意: 请将 ${spring.boot.version} 和 ${spring.data.version} 替换为你想要在项目中使用的 Spring Boot 和 Spring Data 版本。
入门
添加包
如果使用 Maven,请添加以下依赖项。
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-spring-data-cosmos</artifactId>
<version>5.6.0</version>
</dependency>
先决条件
- Java 开发工具包 (JDK) 8 版或更高版本。
- 有效的 Azure 帐户。 如果没有,可以注册 免费帐户。 另外,可使用 Azure Cosmos DB 仿真器进行开发和测试。 由于模拟器 https 证书是自签名证书,因此需要将其证书导入 java 受信任的证书存储, 如此处所述
- (可选)SLF4J 是一种日志外观。
- (可选)SLF4J 绑定用于将特定的记录框架与 SLF4J 相关联。
- (可选)Maven
仅当计划使用日志记录时,才需要 SLF4J。还请下载 SLF4J 绑定,该绑定可将 SLF4J API 与你选择的记录实现链接在一起。 有关详细信息,请参阅 SLF4J 用户手册。
设置配置类
若要设置配置类,需要扩展
AbstractCosmosConfiguration
Azure-spring-data-cosmos 还支持
Response Diagnostics String
、Query Metrics
和Max Degree of Parallelism
。 在 application.properties 中将queryMetricsEnabled
标志设置为 true 以启用查询指标。 除了设置标志,还需要实现ResponseDiagnosticsProcessor
来记录诊断信息。 在 application.properties 中将标志设置为maxDegreeOfParallelism
整数以允许并行处理;将值设置为 -1 将导致 SDK 确定最佳值。 在 application.properties 中将标志设置为maxBufferedItemCount
整数,以允许用户设置在并行查询执行期间可以缓冲的最大项数;如果设置为小于 0,则系统会自动决定要缓冲的项数。 注意:将其设置为非常高的值可能会导致高内存消耗。 在 application.properties 中将标志设置为responseContinuationTokenLimitInKb
整数,以允许用户限制查询响应中继续标记的长度。 继续标记包含必填字段和可选字段。 必填字段是从停止执行的位置恢复执行所必需的。 可选字段可能包含已完成但尚未利用的序列化索引查找工作。 这可避免在后续延续中再次重做工作,从而提高查询性能。 将最大延续大小设置为 1KB,Azure Cosmos DB 服务将仅序列化必填字段。 从 2KB 开始,Azure Cosmos DB 服务将尽可能多地序列化,直到达到指定的最大大小。 设置pointOperationLatencyThresholdInMS
、nonPointOperationLatencyThresholdInMS
requestChargeThresholdInRU
和payloadSizeThresholdInBytes
,以便在超过这些阈值时在客户端级别启用诊断。
@Configuration
@EnableCosmosRepositories
public class AppConfiguration extends AbstractCosmosConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(AppConfiguration.class);
@Value("${azure.cosmos.uri}")
private String uri;
@Value("${azure.cosmos.key}")
private String key;
@Value("${azure.cosmos.secondaryKey}")
private String secondaryKey;
@Value("${azure.cosmos.database}")
private String dbName;
@Value("${azure.cosmos.queryMetricsEnabled}")
private boolean queryMetricsEnabled;
@Value("${azure.cosmos.maxDegreeOfParallelism}")
private int maxDegreeOfParallelism;
@Value("${azure.cosmos.maxBufferedItemCount}")
private int maxBufferedItemCount;
@Value("${azure.cosmos.responseContinuationTokenLimitInKb}")
private int responseContinuationTokenLimitInKb;
@Value("${azure.cosmos.diagnosticsThresholds.pointOperationLatencyThresholdInMS}")
private int pointOperationLatencyThresholdInMS;
@Value("${azure.cosmos.diagnosticsThresholds.nonPointOperationLatencyThresholdInMS}")
private int nonPointOperationLatencyThresholdInMS;
@Value("${azure.cosmos.diagnosticsThresholds.requestChargeThresholdInRU}")
private int requestChargeThresholdInRU;
@Value("${azure.cosmos.diagnosticsThresholds.payloadSizeThresholdInBytes}")
private int payloadSizeThresholdInBytes;
private AzureKeyCredential azureKeyCredential;
@Bean
public CosmosClientBuilder getCosmosClientBuilder() {
this.azureKeyCredential = new AzureKeyCredential(key);
DirectConnectionConfig directConnectionConfig = new DirectConnectionConfig();
GatewayConnectionConfig gatewayConnectionConfig = new GatewayConnectionConfig();
return new CosmosClientBuilder()
.endpoint(uri)
.credential(azureKeyCredential)
.directMode(directConnectionConfig, gatewayConnectionConfig)
.clientTelemetryConfig(
new CosmosClientTelemetryConfig()
.diagnosticsThresholds(
new CosmosDiagnosticsThresholds()
.setNonPointOperationLatencyThreshold(Duration.ofMillis(nonPointOperationLatencyThresholdInMS))
.setPointOperationLatencyThreshold(Duration.ofMillis(pointOperationLatencyThresholdInMS))
.setPayloadSizeThreshold(payloadSizeThresholdInBytes)
.setRequestChargeThreshold(requestChargeThresholdInRU)
)
.diagnosticsHandler(CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER));
}
@Override
public CosmosConfig cosmosConfig() {
return CosmosConfig.builder()
.enableQueryMetrics(queryMetricsEnabled)
.maxDegreeOfParallelism(maxDegreeOfParallelism)
.maxBufferedItemCount(maxBufferedItemCount)
.responseContinuationTokenLimitInKb(responseContinuationTokenLimitInKb)
.responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
.build();
}
public void switchToSecondaryKey() {
this.azureKeyCredential.update(secondaryKey);
}
@Override
protected String getDatabaseName() {
return "testdb";
}
private static class ResponseDiagnosticsProcessorImplementation implements ResponseDiagnosticsProcessor {
@Override
public void processResponseDiagnostics(@Nullable ResponseDiagnostics responseDiagnostics) {
LOGGER.info("Response Diagnostics {}", responseDiagnostics);
}
}
}
自定义配置
可以自定义 DirectConnectionConfig
或或GatewayConnectionConfig
两者,并将它们CosmosClientBuilder
提供给 bean 来自定义 CosmosAsyncClient
。 可以自定义 pointOperationLatencyThresholdInMS
、 nonPointOperationLatencyThresholdInMS
requestChargeThresholdInRU
和 payloadSizeThresholdInBytes
,并自定义诊断日志记录的阈值,与 结合使用CosmosDiagnosticsHandler
时,在添加到 CosmosClientBuilder
时启用具有默认阈值的诊断日志记录。
@Bean
public CosmosClientBuilder getCosmosClientBuilder() {
DirectConnectionConfig directConnectionConfig = new DirectConnectionConfig();
GatewayConnectionConfig gatewayConnectionConfig = new GatewayConnectionConfig();
return new CosmosClientBuilder()
.endpoint(uri)
.directMode(directConnectionConfig, gatewayConnectionConfig)
.clientTelemetryConfig(
new CosmosClientTelemetryConfig()
.diagnosticsThresholds(
new CosmosDiagnosticsThresholds()
.setNonPointOperationLatencyThreshold(Duration.ofMillis(nonPointOperationLatencyThresholdInMS))
.setPointOperationLatencyThreshold(Duration.ofMillis(pointOperationLatencyThresholdInMS))
.setPayloadSizeThreshold(payloadSizeThresholdInBytes)
.setRequestChargeThreshold(requestChargeThresholdInRU)
)
.diagnosticsHandler(CosmosDiagnosticsHandler.DEFAULT_LOGGING_HANDLER));
}
@Override
public CosmosConfig cosmosConfig() {
return CosmosConfig.builder()
.enableQueryMetrics(queryMetricsEnabled)
.maxDegreeOfParallelism(maxDegreeOfParallelism)
.maxBufferedItemCount(maxBufferedItemCount)
.responseContinuationTokenLimitInKb(responseContinuationTokenLimitInKb)
.responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
.build();
}
默认情况下,@EnableCosmosRepositories
将扫描当前包中是否有任何接口用来扩展 Spring Data 的某个存储库接口。
如果项目布局有多个项目,则可使用它来注释配置类,使其按 @EnableCosmosRepositories(basePackageClass=UserRepository.class)
扫描不同的根包。
使用 JavaAgent 启用日志记录诊断以Azure 应用程序 Insights
可以通过将 JavaAgent 与应用程序一起传递来启用诊断,如下所示。 这将启用具有默认阈值的日志记录。 “-javaagent”必须在“-jar”之前传递。
java -javaagent:"<path-to-applicationinsights-agent-jar>" -jar <myapp.jar>
使用数据库预配的吞吐量
Cosmos 支持 容器 和 数据库 预配的吞吐量。 默认情况下,spring-data-cosmos 将为创建的每个容器预配吞吐量。 如果想要在容器之间共享吞吐量,可以通过 CosmosConfig 启用数据库预配的吞吐量。
@Override
public CosmosConfig cosmosConfig() {
int autoscale = false;
int initialRequestUnits = 400;
return CosmosConfig.builder()
.enableDatabaseThroughput(autoscale, initialRequestUnits)
.build();
}
定义实体
将简单实体定义为 Azure Cosmos DB 中的项。
可通过添加
@Container
注释并指定与容器相关的属性(如容器名称、请求单位 (RU)、生存时间和自动创建容器)来定义实体。将自动创建容器,除非你禁止。 若要禁止自动创建容器,请在
@Container
中将autoCreateContainer
设置为 false。注意:默认情况下,分配给新创建的容器的请求单位为 400。 对于 SDK 创建的容器,指定不同的请求单位 (RU) 值来自定义请求单位(RU 值最小为 400)。
@Container(containerName = "myContainer", ru = "400")
public class User {
private String id;
private String firstName;
@PartitionKey
private String lastName;
public User() {
// If you do not want to create a default constructor,
// use annotation @JsonCreator and @JsonProperty in the full args constructor
}
public User(String id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return String.format("User: %s %s, %s", firstName, lastName, id);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
id
字段将用作 Azure Cosmos DB 中的项 ID。 如果要使用其他字段(如firstName
)作为项目id
,只需使用@Id
批注为该字段添加批注即可。注释
@Container(containerName="myContainer")
在 Azure Cosmos DB 中指定容器名称。lastName
字段上的注释@PartitionKey
在 Azure Cosmos DB 中将此字段指定为分区键。
创建具有自动缩放吞吐量的容器
- 注释
autoScale
字段指定要在设置为 true 时创建的带自动缩放吞吐量的容器。 默认值为 false,这意味着会创建带有手动吞吐量的容器。 - 请在此处详细了解自动缩放吞吐量
@Container(containerName = "myContainer", autoScale = true, ru = "4000")
public class UserSample {
@Id
private String emailAddress;
}
嵌套分区键支持
- Azure Spring Data Cosmos 支持嵌套分区键。 若要添加嵌套分区键,请使用
@Container
注释中的partitionKeyPath
字段。 partitionKeyPath
只应用于支持嵌套分区键路径。 对于常规分区键支持,请使用@PartitionKey
注释。- 默认情况下,将优先采用
@PartitionKey
注释(除非未指定)。 - 下面的示例演示如何正确使用嵌套分区键功能。
@Container(containerName = "nested-partition-key", partitionKeyPath = "/nestedEntitySample/nestedPartitionKey")
public class NestedPartitionKeyEntitySample {
private NestedEntitySample nestedEntitySample;
}
public class NestedEntitySample {
private String nestedPartitionKey;
}
创建存储库
扩展了 CosmosRepository 接口,它提供 Spring Data 存储库支持。
@Repository
public interface UserRepository extends CosmosRepository<User, String> {
Iterable<User> findByFirstName(String firstName);
long countByFirstName(String firstName);
User findOne(String id, String lastName);
}
findByFirstName
方法是自定义查询方法,它将按 firstName 查找项。
查询计划缓存
Spring 存储库查询 API(例如 findByFirstName(String firstName)
,其中 firstName
是分区或包含分区键的带批注的查询)将导致查询执行时间降低,因为查询计划缓存。 目前,仅针对单个分区的查询方法支持查询计划缓存。
QueryAnnotation:在存储库中使用带注释的查询
Azure Spring Data Cosmos 支持使用 @Query
在存储库中指定带注释的查询。
- 同步的 CosmosRepository 中带注释的查询示例:
public interface AnnotatedQueriesUserRepositoryCodeSnippet extends CosmosRepository<User, String> {
@Query("select * from c where c.firstName = @firstName and c.lastName = @lastName")
List<User> getUsersByFirstNameAndLastName(@Param("firstName") String firstName, @Param("lastName") String lastName);
@Query("select * from c offset @offset limit @limit")
List<User> getUsersWithOffsetLimit(@Param("offset") int offset, @Param("limit") int limit);
@Query("select value count(1) from c where c.firstName = @firstName")
long getNumberOfUsersWithFirstName(@Param("firstName") String firstName);
}
- ReactiveCosmosRepository 中带注释的查询示例。
public interface AnnotatedQueriesUserReactiveRepositoryCodeSnippet extends ReactiveCosmosRepository<User, String> {
@Query("select * from c where c.firstName = @firstName and c.lastName = @lastName")
Flux<User> getUsersByTitleAndValue(@Param("firstName") int firstName, @Param("lastName") String lastName);
@Query("select * from c offset @offset limit @limit")
Flux<User> getUsersWithOffsetLimit(@Param("offset") int offset, @Param("limit") int limit);
@Query("select count(c.id) as num_ids, c.lastName from c group by c.lastName")
Flux<ObjectNode> getCoursesGroupByDepartment();
@Query("select value count(1) from c where c.lastName = @lastName")
Mono<Long> getNumberOfUsersWithLastName(@Param("lastName") String lastName);
}
注释中指定的查询与 Cosmos 查询相同。 若要详细了解 Cosmos 中的 SQL 查询,请查看以下文章
- [Sql API 查询入门] sql_queries_getting_started
- [Sql API 查询教程] sql_queries_in_cosmos
创建应用程序类
下面创建一个带有所有组件的应用程序类
@SpringBootApplication
public class SampleApplication implements CommandLineRunner {
@Autowired
private UserRepository repository;
@Autowired
private ApplicationContext applicationContext;
public static void main(String[] args) {
SpringApplication.run(SampleApplication.class, args);
}
public void run(String... var1) {
final User testUser = new User("testId", "testFirstName", "testLastName");
repository.deleteAll();
repository.save(testUser);
// to find by Id, please specify partition key value if collection is partitioned
final User result = repository.findOne(testUser.getId(), testUser.getLastName());
// Switch to secondary key
UserRepositoryConfiguration bean =
applicationContext.getBean(UserRepositoryConfiguration.class);
bean.switchToSecondaryKey();
// Now repository will use secondary key
repository.save(testUser);
}
}
- Autowire UserRepository 接口,用于执行保存、删除、查找等操作
- Spring Data Azure Cosmos DB 使用
CosmosTemplate
和ReactiveCosmosTemplate
在查找和保存方法后面执行查询 。 可自行使用模板来执行更复杂的查询。
关键概念
CrudRepository 和 ReactiveCrudRepository
- Azure Spring Data Cosmos 支持 ReactiveCrudRepository 和 CrudRepository,后者提供基本 CRUD 功能
- 保存
- findAll
- 按 ID 查找一个
- deleteAll
- 按 ID 删除
- delete entity
Spring Data 注释
Spring Data @Id 注释
有两种方法将域类中的字段映射到 Azure Cosmos DB 项的 id
字段。
- 使用
@Id
注释域类中的字段,该字段将映射到 Cosmos DB 中的项id
。 - 将该字段的名称设置为
id
,该字段将映射到 Cosmos DB 中的项id
。
ID 自动生成
- 支持使用 @GeneratedValue 注释自动生成字符串类型 UUID。 可以使用 对具有字符串类型 ID 的实体的 id 字段进行
@GeneratedValue
批注,以在插入之前自动生成随机 UUID。
public class GeneratedIdEntity {
@Id
@GeneratedValue
private String id;
}
SpEL 表达式和自定义容器名称。
- 默认情况下,容器名称将是用户域类的类名。 若要对其进行自定义,请将
@Container(containerName="myCustomContainerName")
批注添加到域类中。 容器字段还支持 SpEL 表达式 (例如container = "${dynamic.container.name}"
或container = "#{@someBean.getContainerName()}"
) ,以便以编程方式/通过配置属性提供容器名称。 - 为了使 SpEL 表达式正常工作,需要在 Spring 应用程序类之上添加
@DependsOn("expressionResolver")
。
@SpringBootApplication
@DependsOn("expressionResolver")
public class SampleApplication {
}
索引策略
- 默认情况下,IndexingPolicy 将由 Azure 门户服务设置。 若要对其进行自定义,请将注释
@CosmosIndexingPolicy
添加到域类中。 此批注有 5 个要自定义的属性,请参阅以下内容:
// Indicate if indexing policy use automatic or not
// Default value is true
boolean automatic() default Constants.DEFAULT_INDEXING_POLICY_AUTOMATIC;
// Indexing policy mode, option Consistent.
IndexingMode mode() default IndexingMode.CONSISTENT;
// Included paths for indexing
String[] includePaths() default {};
// Excluded paths for indexing
String[] excludePaths() default {};
唯一密钥策略
- Azure Spring Data Cosmos 支持
UniqueKeyPolicy
通过将 注释@CosmosUniqueKeyPolicy
添加到域类来设置容器。 此批注具有以下属性:
@Container
@CosmosUniqueKeyPolicy(uniqueKeys = {
@CosmosUniqueKey(paths = {"/lastName", "/zipCode"}),
@CosmosUniqueKey(paths = {"/city"})
})
public class CosmosUniqueKeyPolicyCodeSnippet {
@Id
String id;
@PartitionKey
String firstName;
String lastName;
String zipCode;
String city;
}
Azure Cosmos DB 分区
- Azure-spring-data-cosmos 支持 Azure Cosmos DB 分区。
- 若要指定域类的字段作为分区键字段,只需使用
@PartitionKey
来批注它即可。 - 执行 CRUD 操作时,指定分区值。
- 有关分区 CRUD 的更多示例,请参阅此处的测试
乐观锁定
- Azure-spring-data-cosmos 支持对特定容器使用乐观锁定,这意味着按项更新插入/删除将失败,除非该项同时在被另一进程修改。
- 若要为容器启用乐观锁定,只需创建一个字符串
_etag
字段,然后使用@Version
注释标记它即可。 参阅以下内容:
@Container(containerName = "myContainer")
public class MyItem {
String id;
String data;
@Version
String _etag;
}
- 在此处阅读有关乐观锁定的详细信息
Spring Data 自定义查询,可分页和排序
- Azure-spring-data-cosmos 支持 Spring Data 自定义查询
- 例如,
findByAFieldAndBField
等查找操作 - 支持 Spring Data 可分页、切片和排序。
- 根据数据库帐户上提供的 RU,cosmosDB 可能返回小于或等于请求的大小的项。
- 由于每次迭代中返回的项的数目可变,用户不得依赖于 totalPageSize,而应按这种方式循环访问可分页项。
private List<T> findAllWithPageSize(int pageSize) {
final CosmosPageRequest pageRequest = new CosmosPageRequest(0, pageSize, null);
Page<T> page = repository.findAll(pageRequest);
List<T> pageContent = page.getContent();
while (page.hasNext()) {
Pageable nextPageable = page.nextPageable();
page = repository.findAll(nextPageable);
pageContent = page.getContent();
}
return pageContent;
}
public interface SliceQueriesUserRepository extends CosmosRepository<User, String> {
@Query("select * from c where c.lastName = @lastName")
Slice<User> getUsersByLastName(@Param("lastName") String lastName, Pageable pageable);
}
private List<User> getUsersByLastName(String lastName, int pageSize) {
final CosmosPageRequest pageRequest = new CosmosPageRequest(0, pageSize, null);
Slice<User> slice = repository.getUsersByLastName(lastName, pageRequest);
List<User> content = slice.getContent();
while (slice.hasNext()) {
Pageable nextPageable = slice.nextPageable();
slice = repository.getUsersByLastName(lastName, nextPageable);
content.addAll(slice.getContent());
}
return content;
}
Spring Boot Starter 静态数据
- Azure-spring-data-cosmos 支持 spring-boot-starter-data-rest。
- 支持域类中的列表和嵌套类型。
- 具有唯一名称
cosmosObjectMapper
的可配置 ObjectMapper bean,仅在确实需要时才配置自定义 ObjectMapper。例如,
@Bean(name = "cosmosObjectMapper")
public ObjectMapper objectMapper() {
return new ObjectMapper(); // Do configuration to the ObjectMapper if required
}
审核
- Azure-spring-data-cosmos 支持使用标准的 spring-data 注释审核关于数据库实体的字段。
- 可通过向应用程序配置添加
@EnableCosmosAuditing
注释来启用此功能。 - 实体可使用
@CreatedBy
、@CreatedDate
、@LastModifiedBy
和@LastModifiedDate
对字段进行批注。 这些字段将自动更新。
@Container(containerName = "myContainer")
public class AuditableUser {
private String id;
private String firstName;
@CreatedBy
private String createdBy;
@CreatedDate
private OffsetDateTime createdDate;
@LastModifiedBy
private String lastModifiedBy;
@LastModifiedDate
private OffsetDateTime lastModifiedByDate;
}
多数据库配置
- Azure-spring-data-cosmos 支持多数据库配置,包括“多个数据库帐户”和“带有多个数据库的单个帐户”。
多数据库帐户
示例使用 application.properties
文件
# primary account cosmos config
azure.cosmos.primary.uri=your-primary-cosmosDb-uri
azure.cosmos.primary.key=your-primary-cosmosDb-key
azure.cosmos.primary.secondaryKey=your-primary-cosmosDb-secondary-key
azure.cosmos.primary.database=your-primary-cosmosDb-dbName
azure.cosmos.primary.populateQueryMetrics=if-populate-query-metrics
# secondary account cosmos config
azure.cosmos.secondary.uri=your-secondary-cosmosDb-uri
azure.cosmos.secondary.key=your-secondary-cosmosDb-key
azure.cosmos.secondary.secondaryKey=your-secondary-cosmosDb-secondary-key
azure.cosmos.secondary.database=your-secondary-cosmosDb-dbName
azure.cosmos.secondary.populateQueryMetrics=if-populate-query-metrics
@EnableReactiveCosmosRepositories
或@EnableCosmosRepositories
支持由用户定义 Cosmos 模板,使用reactiveCosmosTemplateRef
或cosmosTemplateRef
配置ReactiveCosmosTemplate
或CosmosTemplate
bean 的名称来与删除的存储库一起使用。如果你有多个 Cosmos 数据库帐户,可定义多个
CosmosAsyncClient
。 如果单个 Cosmos 帐户有多个数据库,则可使用相同的CosmosAsyncClient
来初始化 Cosmos 模板。
@Configuration
@EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.multiple.account.repository",
reactiveCosmosTemplateRef = "primaryDatabaseTemplate")
public class PrimaryDatasourceConfiguration extends AbstractCosmosConfiguration{
private static final String PRIMARY_DATABASE = "primary_database";
@Bean
@ConfigurationProperties(prefix = "azure.cosmos.primary")
public CosmosProperties primary() {
return new CosmosProperties();
}
@Bean
public CosmosClientBuilder primaryClientBuilder(@Qualifier("primary") CosmosProperties primaryProperties) {
return new CosmosClientBuilder()
.key(primaryProperties.getKey())
.endpoint(primaryProperties.getUri());
}
@Bean
public ReactiveCosmosTemplate primaryDatabaseTemplate(CosmosAsyncClient cosmosAsyncClient,
CosmosConfig cosmosConfig,
MappingCosmosConverter mappingCosmosConverter) {
return new ReactiveCosmosTemplate(cosmosAsyncClient, PRIMARY_DATABASE, cosmosConfig, mappingCosmosConverter);
}
@Override
protected String getDatabaseName() {
return PRIMARY_DATABASE;
}
}
@Configuration
@EnableCosmosRepositories(cosmosTemplateRef = "secondaryDatabaseTemplate")
public class SecondaryDatasourceConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(SecondaryDatasourceConfiguration.class);
public static final String SECONDARY_DATABASE = "secondary_database";
@Bean
@ConfigurationProperties(prefix = "azure.cosmos.secondary")
public CosmosProperties secondary() {
return new CosmosProperties();
}
@Bean("secondaryCosmosClient")
public CosmosAsyncClient getCosmosAsyncClient(@Qualifier("secondary") CosmosProperties secondaryProperties) {
return CosmosFactory.createCosmosAsyncClient(new CosmosClientBuilder()
.key(secondaryProperties.getKey())
.endpoint(secondaryProperties.getUri()));
}
@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
return CosmosConfig.builder()
.enableQueryMetrics(true)
.maxDegreeOfParallelism(0)
.maxBufferedItemCount(0)
.responseContinuationTokenLimitInKb(0)
.responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
.build();
}
@Bean
public CosmosTemplate secondaryDatabaseTemplate(@Qualifier("secondaryCosmosClient") CosmosAsyncClient client,
@Qualifier("secondaryCosmosConfig") CosmosConfig cosmosConfig,
MappingCosmosConverter mappingCosmosConverter) {
return new CosmosTemplate(client, SECONDARY_DATABASE, cosmosConfig, mappingCosmosConverter);
}
private static class ResponseDiagnosticsProcessorImplementation implements ResponseDiagnosticsProcessor {
@Override
public void processResponseDiagnostics(@Nullable ResponseDiagnostics responseDiagnostics) {
LOGGER.info("Response Diagnostics {}", responseDiagnostics);
}
}
}
- 在上例中,我们有 2 个 Cosmos 帐户。 可创建
CosmosAsyncClient
,如下所示:
@Bean("secondaryCosmosClient")
public CosmosAsyncClient getCosmosAsyncClient(@Qualifier("secondary") CosmosProperties secondaryProperties) {
return CosmosFactory.createCosmosAsyncClient(new CosmosClientBuilder()
.key(secondaryProperties.getKey())
.endpoint(secondaryProperties.getUri()));
}
@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
return CosmosConfig.builder()
.enableQueryMetrics(true)
.maxDegreeOfParallelism(0)
.maxBufferedItemCount(0)
.responseContinuationTokenLimitInKb(0)
.responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
.build();
}
- 此外,如果要定义
queryMetricsEnabled
、ResponseDiagnosticsProcessor
、maxDegreeOfParallelism
maxBufferedItemCount
或responseContinuationTokenLimitInKb
,可以为 cosmos 模板创建CosmosConfig
。
@Bean("secondaryCosmosConfig")
public CosmosConfig getCosmosConfig() {
return CosmosConfig.builder()
.enableQueryMetrics(true)
.maxDegreeOfParallelism(0)
.maxBufferedItemCount(0)
.responseContinuationTokenLimitInKb(0)
.responseDiagnosticsProcessor(new ResponseDiagnosticsProcessorImplementation())
.build();
}
- 创建应用程序类
@SpringBootApplication
public class MultiDatabaseApplication implements CommandLineRunner {
@Autowired
private CosmosUserRepository cosmosUserRepository;
@Autowired
private MysqlUserRepository mysqlUserRepository;
@Autowired
@Qualifier("secondaryDatabaseTemplate")
private CosmosTemplate secondaryDatabaseTemplate;
@Autowired
@Qualifier("primaryDatabaseTemplate")
private ReactiveCosmosTemplate primaryDatabaseTemplate;
private final CosmosUser cosmosUser = new CosmosUser("1024", "1024@geek.com", "1k", "Mars");
private static CosmosEntityInformation<CosmosUser, String> userInfo = new CosmosEntityInformation<>(CosmosUser.class);
public static void main(String[] args) {
SpringApplication.run(MultiDatabaseApplication.class, args);
}
public void run(String... var1) throws Exception {
CosmosUser cosmosUserGet = primaryDatabaseTemplate.findById(cosmosUser.getId(), cosmosUser.getClass()).block();
// Same to this.cosmosUserRepository.findById(cosmosUser.getId()).block();
MysqlUser mysqlUser = new MysqlUser(cosmosUserGet.getId(), cosmosUserGet.getEmail(), cosmosUserGet.getName(), cosmosUserGet.getAddress());
mysqlUserRepository.save(mysqlUser);
mysqlUserRepository.findAll().forEach(System.out::println);
CosmosUser secondaryCosmosUserGet = secondaryDatabaseTemplate.findById(CosmosUser.class.getSimpleName(), cosmosUser.getId(), CosmosUser.class);
System.out.println(secondaryCosmosUserGet);
}
@PostConstruct
public void setup() {
primaryDatabaseTemplate.createContainerIfNotExists(userInfo).block();
primaryDatabaseTemplate.insert(CosmosUser.class.getSimpleName(), cosmosUser, new PartitionKey(cosmosUser.getName())).block();
// Same to this.cosmosUserRepository.save(user).block();
secondaryDatabaseTemplate.createContainerIfNotExists(userInfo);
secondaryDatabaseTemplate.insert(CosmosUser.class.getSimpleName(), cosmosUser, new PartitionKey(cosmosUser.getName()));
}
@PreDestroy
public void cleanup() {
primaryDatabaseTemplate.deleteAll(CosmosUser.class.getSimpleName(), CosmosUser.class).block();
// Same to this.cosmosUserRepository.deleteAll().block();
secondaryDatabaseTemplate.deleteAll(CosmosUser.class.getSimpleName() , CosmosUser.class);
mysqlUserRepository.deleteAll();
}
}
具有多个数据库的单个帐户
示例使用 application.properties
文件
azure.cosmos.uri=your-cosmosDb-uri
azure.cosmos.key=your-cosmosDb-key
azure.cosmos.secondary-key=your-cosmosDb-secondary-key
azure.cosmos.database=your-cosmosDb-dbName
azure.cosmos.populate-query-metrics=if-populate-query-metrics
- 实体和存储库定义与上面的类似。 可将不同的数据库实体放入不同的包中。
- 可将
EnableReactiveCosmosRepositories
与不同的reactiveCosmosTemplateRef
相结合,在一个 Cosmos 帐户中定义多个数据库。
@Configuration
public class DatasourceConfiguration {
private static final String DATABASE1 = "database1";
private static final String DATABASE2 = "database2";
@Bean
public CosmosProperties cosmosProperties() {
return new CosmosProperties();
}
@Bean
public CosmosClientBuilder primaryClientBuilder(CosmosProperties cosmosProperties) {
return new CosmosClientBuilder()
.key(cosmosProperties.getKey())
.endpoint(cosmosProperties.getUri());
}
@EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.repository1",
reactiveCosmosTemplateRef = "database1Template")
public class Database1Configuration extends AbstractCosmosConfiguration {
@Bean
public ReactiveCosmosTemplate database1Template(CosmosAsyncClient cosmosAsyncClient,
CosmosConfig cosmosConfig,
MappingCosmosConverter mappingCosmosConverter) {
return new ReactiveCosmosTemplate(cosmosAsyncClient, DATABASE1, cosmosConfig, mappingCosmosConverter);
}
@Override
protected String getDatabaseName() {
return DATABASE1;
}
}
@EnableReactiveCosmosRepositories(basePackages = "com.azure.spring.sample.cosmos.multi.database.repository2",
reactiveCosmosTemplateRef = "database2Template")
public class Database2Configuration {
@Bean
public ReactiveCosmosTemplate database2Template(CosmosAsyncClient cosmosAsyncClient,
CosmosConfig cosmosConfig,
MappingCosmosConverter mappingCosmosConverter) {
return new ReactiveCosmosTemplate(cosmosAsyncClient, DATABASE2, cosmosConfig, mappingCosmosConverter);
}
}
}
- 创建应用程序类
@SpringBootApplication
public class MultiDatabaseApplication implements CommandLineRunner {
@Autowired
private User1Repository user1Repository;
@Autowired
@Qualifier("database1Template")
private ReactiveCosmosTemplate database1Template;
@Autowired
@Qualifier("database2Template")
private ReactiveCosmosTemplate database2Template;
private final User1 user1 = new User1("1024", "1024@geek.com", "1k", "Mars");
private static CosmosEntityInformation<User1, String> user1Info = new CosmosEntityInformation<>(User1.class);
private final User2 user2 = new User2("2048", "2048@geek.com", "2k", "Mars");
private static CosmosEntityInformation<User2, String> user2Info = new CosmosEntityInformation<>(User2.class);
public static void main(String[] args) {
SpringApplication.run(MultiDatabaseApplication.class, args);
}
public void run(String... var1) throws Exception {
User1 database1UserGet = database1Template.findById(User1.class.getSimpleName(), user1.getId(), User1.class).block();
// Same to userRepository1.findById(user.getId()).block()
System.out.println(database1UserGet);
User2 database2UserGet = database2Template.findById(User2.class.getSimpleName(), user2.getId(), User2.class).block();
System.out.println(database2UserGet);
}
@PostConstruct
public void setup() {
database1Template.createContainerIfNotExists(user1Info).block();
database1Template.insert(User1.class.getSimpleName(), user1, new PartitionKey(user1.getName())).block();
// Same to this.userRepository1.save(user).block();
database2Template.createContainerIfNotExists(user2Info).block();
database2Template.insert(User2.class.getSimpleName(), user2, new PartitionKey(user2.getName())).block();
}
@PreDestroy
public void cleanup() {
database1Template.deleteAll(User1.class.getSimpleName(), User1.class).block();
// Same to this.userRepository1.deleteAll().block();
database2Template.deleteAll(User2.class.getSimpleName(), User2.class).block();
}
}
数据库级别的多租户
- Azure-spring-data-cosmos 通过扩展
CosmosFactory
和重写 getDatabaseName () 函数,支持数据库级别的多租户配置。
public class MultiTenantDBCosmosFactory extends CosmosFactory {
private String tenantId;
/**
* Validate config and initialization
*
* @param cosmosAsyncClient cosmosAsyncClient
* @param databaseName databaseName
*/
public MultiTenantDBCosmosFactory(CosmosAsyncClient cosmosAsyncClient, String databaseName) {
super(cosmosAsyncClient, databaseName);
this.tenantId = databaseName;
}
@Override
public String getDatabaseName() {
return this.getCosmosAsyncClient().getDatabase(this.tenantId).toString();
}
}
Beta 版本包
提供根据 main
分支构建的 Beta 版本,你可参考说明来使用 beta 版本包。
疑难解答
常规
如果遇到任何 bug,请在此处提交问题。
若要建议新功能或可以进行的更改,请以与提交 bug 相同的方式提交问题。
启用客户端日志记录
- Azure-spring-data-cosmos 使用 SLF4j 作为日志外观,支持记录到 log4j 和 logback 等常用的日志框架。 例如,如果你想要将 spring logback 用作日志框架,请在资源文件夹中添加以下 xml。
<configuration>
<include resource="/org/springframework/boot/logging/logback/base.xml"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<logger name="com.azure.cosmos" level="error"/>
<logger name="org.springframework" level="error"/>
<logger name="io.netty" level="error"/>
<!-- This will enable query logging, to include query parameter logging, set this logger to TRACE -->
<logger name="com.azure.cosmos.implementation.SqlQuerySpecLogger" level="DEBUG"/>
</configuration>
示例
- 请参阅此处的示例项目。
多数据库帐户
- 请参阅多数据库示例项目。
具有多个数据库的单个帐户
后续步骤
- 在此处阅读有关 azure spring data cosmos 的详细信息。
- 详细了解 Azure CosmosDB 服务
贡献
本项目欢迎贡献和建议。 大多数贡献要求你同意贡献者许可协议 (CLA),并声明你有权(并且确实有权)授予我们使用你的贡献的权利。
提交拉取请求时,CLA 机器人将自动确定你是否需要提供 CLA,并相应地修饰 PR(例如标签、注释)。 直接按机器人提供的说明操作。 只需使用 CLA 对所有存储库执行一次这样的操作。
此项目采用了 Microsoft 开放源代码行为准则。 有关详细信息,请参阅行为准则常见问题解答,或如果有任何其他问题或意见,请与 联系。