保持领先
VMware 提供培训和认证,助您加速前进。
了解更多这是分为六部分系列文章的第三部分,新的文章会在每周一和周四发布,旨在向 Spring 开发者介绍 Microsoft Azure。如果没有 Microsoft 的 Asir Vedamuthu Selvasingh、Yitao Dong、Bruno Borges、Brian Benz 和 Theresa Nguyen 的帮助,我不可能写出这些文章。你可以在 Github 上找到本系列的示例代码。阅读本系列文章时,如有任何反馈或问题,请随时通过 Twitter (@starbuxman) 联系我。你也可以在我的 Spring Tips (@SpringTipsLive) 文章 Bootiful Azure 中了解更多关于 Microsoft Azure 的信息。
以下是所有文章
我能听到你的想法——是的,即使是你最微弱的念头也逃不过我的耳朵!——虽然你像其他开发者一样喜欢 Microsoft SQL Server,但你完全可以在任何平台(云端或其他!)上自己运行它。你并不需要 Microsoft 为你运行它。对此我会说:“没错!”(但 Microsoft 为我们运行它,难道不是很好吗?)
我承认这一点。那么 Azure 能为你做什么呢?你只需关注 Microsoft Azure CosmosDB 就够了。CosmosDB 指的是一系列技术。它是一个单一的产品,可以以多种方式使用。它是一个单一的、多模型的、多模态的数据库,支持文档数据、SQL 查询、图数据访问等等。
根据产品网页:CosmosDB 从一开始就将全球分发和横向扩展作为其核心。它保证了读写操作在第99个百分位上的单位数毫秒延迟,并通过全球任意位置的多宿主(multi-homing)保证了 99.999% 的高可用性——所有这些都由行业领先的、全面的服务级别协议(SLAs)提供支持。
在内部,CosmosDB 将“条目”(items) 存储在“容器”(containers) 中。但您不一定需要直接处理条目或容器,因为这些概念会呈现在您用来使用数据的特定数据模型的语言中。例如,如果您将其用作文档存储(如 MongoDB),则条目将被映射到集合中的文档。
容器被组织到数据库中,数据库是一种高于容器的命名空间。容器强制执行唯一键约束以确保数据完整性。但容器的功能远不止于此。您可以查询每个容器的更改源 (feed);您可以使用此更改源来实现变更数据捕获 (CDC) 方案。您也可以将此更改源用于事件溯源。该更改源本身是持久化的,因此如果您愿意,可以重放更改。
您还可以为容器指定生存时间 (TTL) 值,让 CosmosDB 在一定时间后自动清除现有记录。您也可以为特定条目覆盖 TTL 设置。
首先,CosmosDB 是无模式的。使用时请记住这一点——如果您没有做好准备,这可能会产生一些重要的影响。
CosmosDB 支持多模型、多范式的方法来构建应用程序。客户端可以通过 HTTP REST API 与其通信,并使用类似 SQL 的语言进行查询。您也可以使用 SQL API 创建、更新和删除容器。
您可以使用 MongoDB API 与 CosmosDB 通信,将集合作为容器,文档作为条目。
您可以使用 Gremlin API 与其通信,将图(graphs)、容器(containers)、节点(nodes)和边(edges)作为条目。根据 Gremlin 网站的说法,“Gremlin 是 Apache TinkerPop 的图遍历语言。Gremlin 是一种函数式数据流语言,使用户能够简洁地在其应用程序的属性图上表达复杂的遍历(或查询)。”因此,它基本上是一种在图中遍历数据的方式。
您可以使用 Cassandra API 与其通信,将表作为容器,行作为条目。Cassandra API 甚至支持 Cassandra 查询语言 (CQL)。
您还可以使用 Azure Table Storage API 与其通信,将表作为容器,将条目作为……嗯……条目。
CosmosDB 还嵌入了一个 JavaScript 引擎,因此您可以使用 JavaScript 定义触发器、可以从 SQL 查询语言调用和扩展的用户定义函数,以及存储过程。存储过程可以在单个 ACID 兼容的事务中管理多个操作。
您首先需要创建一个(可能是地理上分布式的)CosmosDB 实例,然后在其中创建一个数据库实例。接着,您需要创建一个集合来存储记录。这是一个脚本。唯一需要注意的是,我们不必像在 SQL Server 示例中那样指定防火墙例外。它“就是能用”(TM)。
#!/bin/bash
# the name of the resource group
export rg=$1
export adminlogin=${rg}-cosmosdb
location='southcentralus'
accountname=${adminlogin}
databasename=bootiful
containername=reservations
# Create a SQL API Cosmos DB account with session consistency and multi-master enabled
az cosmosdb create \
--resource-group $rg \
--name $adminlogin \
--kind GlobalDocumentDB \
--default-consistency-level "Session"
# Create a database
az cosmosdb database create \
--resource-group $rg \
--name $adminlogin \
--db-name $databasename
# Create a SQL API container with a partition key and 1000 RU/s
az cosmosdb collection create \
--resource-group $rg \
--collection-name $containername \
--name $adminlogin \
--db-name $databasename \
--partition-key-path /id \
--throughput 1000
在这个脚本中,我们可以指定希望新数据库可用的区域。您也可以通过便捷的地图在 Azure 门户中方便地完成此操作。只需点击一个区域,剩下的就都交给它了!
另外,请记下随后产生的 $adminlogin
值,以便后续使用。
现在,您需要获取必要的配置字符串,以便将您的应用程序连接到新的数据库及其数据。您可以仔细查看之前命令的输出,但下面的命令要简单得多。
az cosmosdb list-keys --resource-group bootiful --name bootiful-cosmosdb
为了稍后连接到 CosmosDB,您需要记下上一个命令产生的 primaryMasterKey
属性值。
让我们看看如何在 Spring 应用程序中使用 CosmosDB。理论上,您可以通过上述技术(如 MongoDB 和 Cassandra)的相应抽象来与 CosmosDB 通信。我更喜欢使用 Spring Data CosmosDB 抽象,您需要将其启动器依赖添加到构建文件中。
CosmosDB 历史上称为 DocumentDB。如果您看到这些名称,它们几乎可以互换。出于历史原因,您需要将引用旧项目名称 com.microsoft.azure
:azure-documentdb-spring-boot-starter
的 Maven 启动器依赖添加到您的构建文件中。
然后您必须配置相关的连接信息。您可以将以下内容添加到您的应用程序的 application.properties
文件中。
azure.documentdb.database=bootiful
azure.documentdb.key=THIS_IS_THE_KEY_FROM_BEFORE
azure.documentdb.uri=https://ADMINLOGIN.documents.azure.com:443/
database
属性指的是逻辑 CosmosDB 实例(bootiful-cosmosdb
,这是我们在脚本中用 $adminlogin
指定的)内的数据库(bootiful
,因为我们将资源组名称用作数据库名称)。key
指的是 az cosmosdb list-keys
命令中的 primaryMasterKey
值。请将属性值替换为相关且适当的字符串值。
我在基于 macOS 的系统上运行这个项目没有任何问题,但在我基于 Ubuntu 18.10 的系统上运行它时遇到了一个奇怪的问题。Spring CosmosDB 客户端库收集遥测数据的方式存在一个异常,导致了 NPE。如果您遇到此问题,请将以下内容添加到 src/main/resources/application.properties
中以禁用遥测功能。
cosmosdb.telemetryAllowed=false
接下来,您应该定义一个 Spring Data 实体,将其映射到 CosmosDB 集合 reservations
中的记录。
package com.example.bootifulazure;
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.Document;
import com.microsoft.azure.spring.data.cosmosdb.core.mapping.PartitionKey;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "reservations")
class Reservation {
@PartitionKey
private String id;
private String name;
}
大多数情况下,这看起来就像您见过的任何其他使用 Lombok 注解的 POJO。特别值得注意的是,该实体使用了 Spring Data CosmosDB 模块中的 @Document
注解来指定此实体映射到的 reservations
集合。该实体使用一个 CosmosDB 特定的注解 @PartitionKey
来向数据库指示在决定如何分区(逻辑上或物理上)容器中可能相关的数据时应使用哪个字段。对于分区键,使用 String
类型是一个很好的实践。在行星规模的分布式系统中,单调递增的主键不是一个好主意!
现在,定义基于 DocumentDbRepository
的 Spring Data 仓库。
package com.example.bootifulazure;
import com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository;
interface ReservationRepository extends DocumentDbRepository<Reservation, String> {
}
DocumentDbRepository
可能是一个新概念,但除此之外,这应该是直截了当的。
package com.example.bootifulazure;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.stream.Stream;
@Log4j2
@Component
class CosmosDbDemo {
private final ReservationRepository rr;
CosmosDbDemo(ReservationRepository rr) {
this.rr = rr;
}
@EventListener(ApplicationReadyEvent.class)
public void demo() throws Exception {
this.rr.deleteAll();
Stream.of("A", "B", "C")
.map(name -> new Reservation(UUID.randomUUID().toString(), name))
.map(this.rr::save)
.forEach(log::info);
}
}