领先一步
VMware 提供培训和认证,助您加速进步。
了解更多这是 6 部分系列文章的第 3 部分,新文章将在每周一和周四发布,介绍面向 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 Cosmos DB 就知道了。Cosmos DB 指的是一套技术。它描述了一个可以以多种方式使用的单一产品。它是一个单一的、多模型、多模态的数据库,支持文档数据、SQL 查询、图数据访问等。
根据 产品网页:Cosmos DB 从一开始就以全局分发和水平扩展为核心构建。它保证在 99% 的百分位上具有个位数毫秒的读写延迟,并保证在全球任何地方都具有 99.999% 的高可用性,并且支持多宿主——所有这些都由行业领先的、全面的服务级别协议 (SLA) 提供支持。
在内部,Cosmos DB 将“项”存储在“容器”中。但您不一定需要将项或容器作为您正在使用的、用于消费数据的模型语言所暴露的概念来处理。如果您将其用作文档存储,例如 MongoDB,那么项将被映射到集合中的文档。
容器被分组到数据库中,数据库是容器之上的一种命名空间。容器强制执行唯一键约束以确保数据的完整性。但容器的功能远不止于此。您可以让每个容器提供更改的流;您可以使用此流来实现变更数据捕获 (CDC) 方案。您也可以使用此流来实现事件溯源。此流本身是持久化的,因此您可以重放更改,如果您愿意的话。
您还可以为容器指定生存时间 (TTL) 值,让 Cosmos DB 在特定时间段后自动删除现有记录。您也可以为特定项覆盖 TTL。
首先,Cosmos DB 是无模式的。在使用它时请牢记这一点——如果您没有准备好,它可能会产生一些重要的影响。
Cosmos DB 支持多模型、多范式的方法来构建应用程序。客户端可以通过 HTTP REST API 与之交互,并使用类 SQL 的语言进行查询。您也可以使用 SQL API 创建、更新和删除容器。
您可以通过 MongoDB API 与 Cosmos DB 进行交互,将集合作为容器,将文档作为项。
您可以通过 Gremlin API 与之交互,支持将图、容器、节点和边作为项。根据 Gremlin 网站的说法,“Gremlin 是 Apache TinkerPop 的图遍历语言。Gremlin 是一种函数式、数据流语言,使用户能够简洁地表达对其应用程序属性图的复杂遍历(或查询)。” 因此,它基本上是一种遍历图数据的方式。
您可以通过 Cassandra API 与 Cosmos DB 进行交互,支持将表作为容器,将行作为项。Cassandra API 甚至支持 Cassandra 查询语言 (CQL)。
您还可以通过 Azure Table Storage API 与之交互,支持将表作为容器,将项作为……好吧……项。
Cosmos DB 还嵌入了一个 JavaScript 引擎,因此您可以使用 JavaScript 定义触发器、可以从 SQL 查询语言调用并增强 SQL 查询语言的用户定义函数以及存储过程。存储过程可以在单个 ACID 兼容事务中管理多个操作。
您需要首先创建一个(可能是地理分布的)Cosmos DB 实例,然后在其中创建一个数据库实例。然后,您需要创建一个集合来存储记录。这是一个脚本。唯一值得注意的是,我们不必像在 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 Portal 中的一个便捷地图来完成此操作。只需单击一个区域,它就会处理其余的事情!
另外,请记下稍后需要使用的 `$adminlogin` 值。
现在,您需要获取必要的连接字符串,以便将您的应用程序连接到新的数据库及其数据。您可以查看前面命令的输出,但以下命令会更容易得多。
az cosmosdb list-keys --resource-group bootiful --name bootiful-cosmosdb
您需要记下前面命令生成的 `primaryMasterKey` 属性值,以便稍后连接到 Cosmos DB。
让我们看看 Cosmos DB 在 Spring 应用程序中的用法。理论上,您可以通过上述技术的相应抽象(如 MongoDB 和 Cassandra)来与 Cosmos DB 进行交互。我更喜欢使用 Spring Data Cosmos DB 抽象,您需要在构建文件中添加其启动器依赖项。
Cosmos DB 以前被称为 DocumentDB。如果您看到这些名称,它们几乎可以互换使用。出于历史原因,您需要将引用旧项目名称 `com.microsoft.azure` 的 Maven 启动器依赖项 `azure-documentdb-spring-boot-starter` 添加到您的构建文件中。
然后,您必须配置相关的连接信息。您可以将以下内容添加到应用程序的 `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` 属性指的是逻辑 Cosmos DB 实例(`bootiful-cosmosdb`,这是我们在脚本中通过 `$adminlogin` 指定的)内的数据库(`bootiful`,因为我们使用了资源组名称作为数据库名称)。`key` 指的是 `az cosmosdb list-keys` 命令中的 `primaryMasterKey` 值。请将属性值替换为相关且适当的字符串值。
我在基于 macOS 的系统上成功运行了此项目,但在基于 Ubuntu 18.10 的系统上遇到了一些奇怪的问题。Spring 客户端库用于 Cosmos DB 的遥测数据收集方式存在一些怪异之处,会导致 NPE。如果您遇到这种情况,请在 `src/main/resources/application.properties` 中添加以下内容来禁用遥测数据。
cosmosdb.telemetryAllowed=false
接下来,您应该定义一个 Spring Data 实体来映射到 Cosmos DB 集合 `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 Cosmos DB 模块中的 `@Document` 来指定映射到此实体的 `reservations` 集合。该实体使用 Cosmos DB 特定的注释 `@PartitionKey`,来告知数据库在分区(逻辑上或物理上)容器中可能相关的数据时使用哪个字段。使用字符串作为分区键是一个好习惯。在行星规模的分布式系统中,单调递增的主键不是一个好主意!
现在,定义一个基于 `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);
}
}