0
点赞
收藏
分享

微信扫一扫

Spring Cloud GCP(三)

Spring Cloud GCP(三)_java

13. 弹簧数据云扳手

Spring 数据是用于在众多存储技术中存储和检索 POJO 的抽象。 Spring Cloud GCP 增加了对Google Cloud Spanner 的 Spring Data 支持。

Maven 仅使用此模块的坐标,使用Spring Cloud GCP BOM:

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-data-spanner</artifactId>
</dependency>

格拉德尔坐标:

dependencies {
implementation("com.google.cloud:spring-cloud-gcp-data-spanner")
}

我们为SpringData Spanner提供了一个Spring Boot Starter,您可以使用它利用我们推荐的自动配置设置。 要使用启动器,请参阅下面的坐标。

专家:

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-data-spanner</artifactId>
</dependency>

格拉德尔:

dependencies {
implementation("com.google.cloud:spring-cloud-gcp-starter-data-spanner")
}

此设置还负责引入Cloud Java Cloud Spanner库的最新兼容版本。

13.1. 配置

要设置 Spring Data Cloud Spanner,您必须配置以下内容:

  • 设置与 Google Cloud Spanner 的连接详细信息。
  • 启用 Spring 数据存储库(可选)。

13.1.1. 云扳手设置

您可以使用Spring Boot Starter for Spring Data Spanner在Spring应用程序中自动配置Google Cloud Spanner。 它包含所有必要的设置,使您可以轻松地使用Google云项目进行身份验证。 以下配置选项可用:

名字

描述

必填

默认值

​spring.cloud.gcp.spanner.enabled​

启用云扳手客户端

​true​

​spring.cloud.gcp.spanner.instance-id​

要使用的云扳手实例

是的

​spring.cloud.gcp.spanner.database​

要使用的云扳手数据库

是的

​spring.cloud.gcp.spanner.project-id​

托管 Google Cloud Spanner API 的 GCP 项目 ID(如果与Spring Cloud GCP 核心模块中的 ID 不同)

​spring.cloud.gcp.spanner.credentials.location​

用于使用 Google Cloud Spanner API,如果与Spring Cloud GCP Core Module中的API不同

​spring.cloud.gcp.spanner.credentials.encoded-key​

用于使用 Google Cloud Spanner API,如果与Spring Cloud GCP Core Module中的API不同

​spring.cloud.gcp.spanner.credentials.scopes​

春季云 GCP 的 OAuth2 范围 云扳手凭据

www.googleapis.com/auth/spanner.data

​spring.cloud.gcp.spanner.createInterleavedTableDdlOnDeleteCascade​

如果,则由具有交错父子关系的 for 表生成的架构语句将为“ON DELETE CASCADE”。 表的架构将为“删除时不执行任何操作”。​​true​​​​SpannerSchemaUtils​​​​false​

​true​

​spring.cloud.gcp.spanner.numRpcChannels​

用于连接到 Cloud Spanner 的 gRPC 通道数

4 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.prefetchChunks​

Cloud Spanner 预取的用于读取和查询的区块数

4 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.minSessions​

会话池中维护的最小会话数

0 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.maxSessions​

会话池可以具有的最大会话数

400 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.maxIdleSessions​

会话池将保持的最大空闲会话数

0 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.writeSessionsFraction​

为写入事务准备的会话数

0.2 - 由 Cloud Spanner 客户端库确定

​spring.cloud.gcp.spanner.keepAliveIntervalMinutes​

使空闲会话保持活动状态多长时间

30 - 由云扳手客户端库确定

​spring.cloud.gcp.spanner.failIfPoolExhausted​

如果所有会话都在使用中,则通过引发异常使请求失败。否则,默认情况下,在会话可用之前阻止。

​false​

​spring.cloud.gcp.spanner.emulator.enabled​

启用模拟器的使用。如果设置为 true,则应将本地运行的模拟器实例的 host:port 设置为。​​spring.cloud.gcp.spanner.emulator-host​

​false​

​spring.cloud.gcp.spanner.emulator-host​

扳手模拟器的主机和端口;可以重写以指定连接到已在运行的Spanner 模拟器实例。

​localhost:9010​

要进一步定制客户端库,请提供一个 Bean 实现,其中包含接受 a并根据需要对其进行修改的单个方法。​​SpannerOptions​​​​SpannerOptionsCustomizer​​​​SpannerOptions.Builder​

13.1.2. 仓库设置

Spring 数据存储库可以通过主类上的注释进行配置。 使用我们的 Spring Boot Starter for Spring Data Cloud Spanner,会自动添加。 不需要将其添加到任何其他类中,除非需要覆盖 @EnableSpannerRepositories 提供的更细粒度的配置参数。​​@EnableSpannerRepositories​​​​@Configuration​​​​@EnableSpannerRepositories​

13.1.3. 自动配置

我们的 Spring 引导自动配置在 Spring 应用程序上下文中创建以下可用的 bean:

  • 的实例SpannerTemplate
  • 的实例用于从对象层次结构生成表架构以及创建和删除表和数据库SpannerDatabaseAdminTemplate
  • 启用存储库时扩展的所有用户定义存储库的实例,,,存储库SpannerRepositoryCrudRepositoryPagingAndSortingRepository
  • 来自 Google Cloud Java Client for Spanner 的实例,为了方便和较低级别的 API 访问DatabaseClient

13.2. 对象映射

Spring Data Cloud Spanner 允许您通过注释将域 POJO 映射到 Cloud Spanner 表:

@Table(name = "traders")
public class Trader {

@PrimaryKey
@Column(name = "trader_id")
String traderId;

String firstName;

String lastName;

@NotMapped
Double temporaryNumber;
}

Spring Data Cloud Spanner将忽略任何注释的属性。 这些属性不会写入或读取 Spanner。​​@NotMapped​

13.2.1. 构造函数

POJO 支持简单的构造函数。 构造函数参数可以是持久性属性的子集。 每个构造函数参数都需要具有与实体上的持久属性相同的名称和类型,构造函数应从给定参数设置属性。 不支持未直接设置为属性的参数。

@Table(name = "traders")
public class Trader {
@PrimaryKey
@Column(name = "trader_id")
String traderId;

String firstName;

String lastName;

@NotMapped
Double temporaryNumber;

public Trader(String traderId, String firstName) {
this.traderId = traderId;
this.firstName = firstName;
}
}

13.2.2. 表

注释可以提供 Cloud Spanner 表的名称,该表存储带注释类的实例,每行一个。 此注释是可选的,如果未给出,则从第一个字符未大写的类名推断表的名称。@Table

表名的 SpEL 表达式

在某些情况下,您可能希望动态确定表名。 为此,您可以使用Spring Expression Language。​​@Table​

例如:

@Table(name = "trades_#{tableNameSuffix}")
public class Trade {
// ...
}

仅当定义了 Spring 应用程序上下文中的值/bean 时,才会解析表名。 例如,如果值为“123”,则表名将解析为。​​tableNameSuffix​​​​tableNameSuffix​​​​trades_123​

13.2.3. 主键

对于简单表,您可能只有一个由单个列组成的主键。 即使在这种情况下,也需要注释。标识与主键对应的一个或多个 ID 属性。​​@PrimaryKey​​​​@PrimaryKey​

Spanner 对多列的复合主键具有一流的支持。 您必须注释主键包含的所有POJO字段,如下所示:​​@PrimaryKey​

@Table(name = "trades")
public class Trade {
@PrimaryKey(keyOrder = 2)
@Column(name = "trade_id")
private String tradeId;

@PrimaryKey(keyOrder = 1)
@Column(name = "trader_id")
private String traderId;

private String action;

private BigDecimal price;

private Double shares;

private String symbol;
}

参数按顺序标识与主键列对应的属性,从 1 开始并连续递增。 顺序很重要,必须反映云扳手架构中定义的顺序。 在我们的示例中,用于创建表及其主键的 DDL 如下所示:​​keyOrder​​​​@PrimaryKey​

CREATE TABLE trades (
trader_id STRING(MAX),
trade_id STRING(MAX),
action STRING(15),
symbol STRING(10),
price NUMERIC,
shares FLOAT64
) PRIMARY KEY (trader_id, trade_id)

扳手没有自动生成 ID。 对于大多数用例,应谨慎使用顺序 ID,以避免在系统中创建数据热点。 阅读Spanner主键文档,以更好地了解主键和建议的做法。

13.2.4. 列

POJO 上的所有可访问属性都会自动识别为云扳手列。 列命名由 thebean 上默认定义。 注释可以选择提供与属性和一些其他设置不同的列名:​​PropertyNameFieldNamingStrategy​​​​SpannerMappingContext​​​​@Column​

  • ​name​​是列的可选名称
  • ​spannerTypeMaxLength​​指定 forandcolumns 的最大长度。 此设置仅在基于域类型生成 DDL 架构语句时使用。STRINGBYTES
  • ​nullable​​指定是否将列创建为。 此设置仅在基于域类型生成 DDL 架构语句时使用。NOT NULL
  • ​spannerType​​是您可以选择指定的云扳手列类型。 如果未指定,则从 Java 属性类型推断出兼容的列类型。
  • ​spannerCommitTimestamp​​是一个布尔值,指定此属性是否对应于自动填充的提交时间戳列。 写入云扳手时,将忽略此属性中设置的任何值。

13.2.5. 嵌入对象

如果 type 的对象嵌入为 的属性,则 的列将保存在与 of 相同的 Cloud Spanner 表中。​​B​​​​A​​​​B​​​​A​

如果具有主键列,则这些列将包含在主键中。也可以具有嵌入的属性。 嵌入允许在多个实体之间重用列,并且对于实现父子情况非常有用,因为 Cloud Spanner 要求子表包含其父表的键列。​​B​​​​A​​​​B​

例如:

class X {
@PrimaryKey
String grandParentId;

long age;
}

class A {
@PrimaryKey
@Embedded
X grandParent;

@PrimaryKey(keyOrder = 2)
String parentId;

String value;
}

@Table(name = "items")
class B {
@PrimaryKey
@Embedded
A parent;

@PrimaryKey(keyOrder = 2)
String id;

@Column(name = "child_value")
String value;
}

实体可以存储在定义为以下的表中:​​B​

CREATE TABLE items (
grandParentId STRING(MAX),
parentId STRING(MAX),
id STRING(MAX),
value STRING(MAX),
child_value STRING(MAX),
age INT64
) PRIMARY KEY (grandParentId, parentId, id)

请注意,使用嵌入对象时,存在以下限制:

  • 嵌入属性的列名称必须全部唯一。
  • 嵌入属性不得通过构造函数传递,并且该属性必须是可变的;否则,您将收到错误,例如。 当您使用 Kotlin 的数据类来保存嵌入属性时,请注意此限制。SpannerDataException: Column not found

13.2.6. 关系

Spring Data Cloud Spanner 支持使用云扳手父子交错表机制的父子关系。 Cloud Spanner 交错表强制执行一对多关系,并对单个域父实体的实体提供高效的查询和操作。 这些关系最多可以有 7 个级别。 Cloud Spanner 还提供自动级联删除或强制删除子实体,然后再删除父实体。

虽然可以使用交错父子表的构造在 Cloud Spanner 和 Spring Data Cloud Spanner 中实现一对一和多对多关系,但本机仅支持父子关系。

例如,以下 Java 实体:

@Table(name = "Singers")
class Singer {
@PrimaryKey
long SingerId;

String FirstName;

String LastName;

byte[] SingerInfo;

@Interleaved
List<Album> albums;
}

@Table(name = "Albums")
class Album {
@PrimaryKey
long SingerId;

@PrimaryKey(keyOrder = 2)
long AlbumId;

String AlbumTitle;
}

这些类可以对应于现有的一对交错表。 注释可以应用于属性,内部类型解析为子实体类型。 创建它们所需的架构也可以使用 和 使用以下方法运行:​​@Interleaved​​​​Collection​​​​SpannerSchemaUtils​​​​SpannerDatabaseAdminTemplate​

@Autowired
SpannerSchemaUtils schemaUtils;

@Autowired
SpannerDatabaseAdminTemplate databaseAdmin;
...

// Get the create statmenets for all tables in the table structure rooted at Singer
List<String> createStrings = this.schemaUtils.getCreateTableDdlStringsForInterleavedHierarchy(Singer.class);

// Create the tables and also create the database if necessary
this.databaseAdmin.executeDdlStrings(createStrings, true);

Thelist 包含表架构语句,这些语句使用与提供的 Java 类型兼容的列名和类型,以及基于配置的自定义转换器包含的任何已解析子关系类型。​​createStrings​

CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

该子句表示,如果歌手被删除,Cloud Spanner 将删除该歌手的所有专辑。 另一种方法是,在删除所有专辑之前,无法删除歌手。 用于生成架构字符串时,布尔设置确定是否按原样生成这些架构。​​ON DELETE CASCADE​​​​ON DELETE NO ACTION​​​​SpannerSchemaUtils​​​​spring.cloud.gcp.spanner.createInterleavedTableDdlOnDeleteCascade​​​​ON DELETE CASCADE​​​​true​​​​ON DELETE NO ACTION​​​​false​

Cloud Spanner 将这些关系限制为 7 个子层。 一个表可以有多个子表。

在将对象更新或插入到 Cloud Spanner 时,其所有引用的子对象也会分别更新或插入到同一请求中。 读取时,所有交错的子行也会全部读取。

懒惰获取

​@Interleaved​​默认情况下,属性是急切检索的,但可以延迟获取以实现读取和写入性能:

@Interleaved(lazy = true)
List<Album> albums;

延迟提取的交错属性在与属性的第一次交互时检索。 如果从未检索到标记为延迟获取的属性,则在保存父实体时也会跳过该属性。

如果在事务中使用,则对延迟提取的属性的后续操作使用与原始父实体相同的事务上下文。

声明性筛选@Where

注释可以应用于实体类或交错属性。 此注释提供了一个 SQL where 子句,该子句将在获取交错集合或实体本身时应用。​​@Where​

假设我们有一个可以分配给它的列表。 我们想获取当前活跃参与者的列表。 出于安全原因,所有记录都应永久保留在数据库中,即使参与者变得不活动。 这可以通过注释轻松实现,此示例演示了:​​Agreement​​​​Participants​​​​@Where​

@Table(name = "participants")
public class Participant {
//...
boolean active;
//...
}

@Table(name = "agreements")
public class Agreement {
//...
@Interleaved
@Where("active = true")
List<Participant> participants;
Person person;
//...
}

13.2.7. 支持的类型

Spring Data Cloud Spanner原生支持常规字段的以下类型,但也利用自定义转换器(详见以下部分)和数十个预定义的Spring Data自定义转换器来处理其他常见的Java类型。

本机支持的类型:

  • ​com.google.cloud.ByteArray​
  • ​com.google.cloud.Date​
  • ​com.google.cloud.Timestamp​
  • ​java.lang.Boolean​​, boolean
  • ​java.lang.Double​​, double
  • ​java.lang.Long​​, long
  • ​java.lang.Integer​​, int
  • ​java.lang.String​
  • ​double[]​
  • ​long[]​
  • ​boolean[]​
  • ​java.util.Date​
  • ​java.time.Instant​
  • ​java.sql.Date​
  • ​java.time.LocalDate​
  • ​java.time.LocalDateTime​

13.2.8. JSON 字段

扳手支持列的沙型。此类属性需要用 进行批注。列映射到自定义 POJO,列映射到自定义 POJO 列表。JSON 带注释的字段支持使用自定义 SQL 查询进行读取、写入和查询。​​JSON​​​​ARRAY<JSON>​​​​@Column(spannerType = TypeCode.JSON)​​​​JSON​​​​ARRAY<JSON>​

默认情况下,Spring Boot 会自动配置 abean。 默认情况下,此 Gson 实例用于与 JSON 表示形式相互转换。 要进行自定义,请按照此处的​ Spring 引导文档中的说明使用配置属性或 bean。 或者,您也可以在应用程序中提供自定义的类型 Bean。​​Gson​​​​spring.gson.*​​​​GsonBuilderCustomizer​​​​Gson​

@Table(name = "traders")
public class Trader {

@PrimaryKey
@Column(name = "trader_id")
String traderId;

@Column(spannerType = TypeCode.JSON)
Details details;
}

public class Details {
String name;
String affiliation;
Boolean isActive;
}

13.2.9. 列表

Spanner 支持列的类型。列映射到 POJO 中的字段。​​ARRAY​​​​ARRAY​​​​List​

例:

List<Double> curve;

列表中的类型可以是任何单一属性类型。

13.2.10. 结构列表

云扳手查询可以构造在结果中显示为列的STRUCT 值。 Cloud Spanner 要求 STRUCT 值出现在根级别的 ARRAY 中:​​SELECT ARRAY(SELECT STRUCT(1 as val1, 2 as val2)) as pair FROM Users​

Spring Data Cloud Spanner 将尝试将列 STRUCT 值读入一个属性中,该属性是与列 STRUCT 值的模式兼容的实体类型。​​Iterable​

对于前面的数组选择示例,可以使用构造列映射以下属性:其中定义了类型:​​ARRAY<STRUCT>​​​​List<TwoInts> pair;​​​​TwoInts​

class TwoInts {

int val1;

int val2;
}

13.2.11. 自定义类型

自定义转换器可用于扩展对用户定义类型的类型支持。

  1. 转换器需要在两个方向上实现接口。org.springframework.core.convert.converter.Converter
  2. 用户定义类型需要映射到 Spanner 支持的基本类型之一:
  • ​com.google.cloud.ByteArray​
  • ​com.google.cloud.Date​
  • ​com.google.cloud.Timestamp​
  • ​java.lang.Boolean​​, boolean
  • ​java.lang.Double​​, double
  • ​java.lang.Long​​, long
  • ​java.lang.String​
  • ​double[]​
  • ​long[]​
  • ​boolean[]​
  • ​enum​​类型
  1. 两个转换器的实例都需要传递给 a,然后必须将其作为 afor 提供。ConverterAwareMappingSpannerEntityProcessor@BeanSpannerEntityProcessor

例如:

我们希望在我们的POJO上有一个类型字段:​​Person​​​​Trade​

@Table(name = "trades")
public class Trade {
//...
Person person;
//...
}

其中 Person 是一个简单的类:

public class Person {

public String firstName;
public String lastName;

}

我们必须定义两个转换器:

public class PersonWriteConverter implements Converter<Person, String> {

@Override
public String convert(Person person) {
return person.firstName + " " + person.lastName;
}
}

public class PersonReadConverter implements Converter<String, Person> {

@Override
public Person convert(String s) {
Person person = new Person();
person.firstName = s.split(" ")[0];
person.lastName = s.split(" ")[1];
return person;
}
}

这将在我们的文件中配置:​​@Configuration​

@Configuration
public class ConverterConfiguration {

@Bean
public SpannerEntityProcessor spannerEntityProcessor(SpannerMappingContext spannerMappingContext) {
return new ConverterAwareMappingSpannerEntityProcessor(spannerMappingContext,
Arrays.asList(new PersonWriteConverter()),
Arrays.asList(new PersonReadConverter()));
}
}

请注意,它需要用于写入和读取操作的转换器列表,以支持多个用户定义类型。 当列表中存在用户定义类的重复转换器时,它将选择列表中的第一个匹配项。 这意味着,对于用户定义的类,写入操作使用第一个来自写入转换器,读取操作使用第一个来自读取转换器。​​ConverterAwareMappingSpannerEntityProcessor​​​​U​​​​Converter<U, …>​​​​Converter<…, U>​

13.2.12. 结构数组列的自定义转换器

如果提供了 ais,则类型的属性可以在实体类型中使用。​​Converter<Struct, A>​​​​List<A>​

13.3. 扳手操作和模板

​SpannerOperations​​及其实现提供了 Spring 开发人员熟悉的模板模式。 它提供:​​SpannerTemplate​

  • 资源管理
  • 具有Spring Data POJO映射和转换功能的一站式扳手操作
  • 异常转换

使用我们的 Spring Boot Starter for Spanner 提供的,您的 Spring 应用程序上下文将包含一个完全配置的对象,您可以在应用程序中轻松自动连线:​​autoconfigure​​​​SpannerTemplate​

@SpringBootApplication
public class SpannerTemplateExample {

@Autowired
SpannerTemplate spannerTemplate;

public void doSomething() {
this.spannerTemplate.delete(Trade.class, KeySet.all());
//...
Trade t = new Trade();
//...
this.spannerTemplate.insert(t);
//...
List<Trade> tradesByAction = spannerTemplate.findAll(Trade.class);
//...
}
}

模板 API 为以下各项提供了方便的方法:

  • 读取,并通过提供 SpannerReadOptions 和 扳手查询选项
  • 过时读取
  • 使用二级索引读取
  • 使用限制和偏移量读取
  • 通过排序读取
  • 查询
  • DML 操作(删除、插入、更新、更新插入)
  • 部分读取
  • 您可以定义一组要读入实体的列
  • 部分写入
  • 仅保留实体中的几个属性
  • 只读事务
  • 锁定读写事务

13.3.1.SQL 查询

Cloud Spanner 具有运行只读查询的 SQL 支持。 所有与查询相关的方法都以 on 开头。 通过使用,您可以运行映射到 POJO 的 SQL 查询:​​query​​​​SpannerTemplate​​​​SpannerTemplate​

List<Trade> trades = this.spannerTemplate.query(Trade.class, Statement.of("SELECT * FROM trades"));

13.3.2. 读取

Spanner 公开了一个读取 API,用于读取表或二级索引中的单行或多行。

使用您可以运行读取,如以下示例所示:SpannerTemplate

List<Trade> trades = this.spannerTemplate.readAll(Trade.class);

通过查询进行读取的主要好处是,使用KeySet类的功能可以更轻松地读取特定模式键的多行。

13.3.3. 高级读取

过时读取

默认情况下,所有读取和查询都是强读取。 强读取是当前时间的读取,保证查看在此读取开始之前已提交的所有数据。 确切的过期读取是在过去时间戳处读取的。 Cloud Spanner 允许您确定读取数据时数据的最新程度。 有了,您可以通过设置它来指定适当的读取或查询方法:​​SpannerTemplate​​​​Timestamp​​​​SpannerQueryOptions​​​​SpannerReadOptions​

读:

// a read with options:
SpannerReadOptions spannerReadOptions = new SpannerReadOptions().setTimestamp(myTimestamp);
List<Trade> trades = this.spannerTemplate.readAll(Trade.class, spannerReadOptions);

查询:

// a query with options:
SpannerQueryOptions spannerQueryOptions = new SpannerQueryOptions().setTimestamp(myTimestamp);
List<Trade> trades = this.spannerTemplate.query(Trade.class, Statement.of("SELECT * FROM trades"), spannerQueryOptions);

还可以通过设置查询和读取选项对象来读取有限过期的读取。 有界过期允许 Cloud Spanner 选择晚于或等于给定时间戳的任何时间点,但它不能在事务中使用。​​.setTimestampBound(TimestampBound.ofMinReadTimestamp(myTimestamp))​

从二级索引读取

使用二级索引可用于通过模板 API 进行读取,也可以通过 SQL 进行查询隐式使用。

下面显示了如何通过设置使用二级索引从表中读取行:​​index​​​​SpannerReadOptions​

SpannerReadOptions spannerReadOptions = new SpannerReadOptions().setIndex("TradesByTrader");
List<Trade> trades = this.spannerTemplate.readAll(Trade.class, spannerReadOptions);

使用偏移和限制读取

限制和偏移量仅受查询支持。 以下内容将仅获取查询的前两行:

SpannerQueryOptions spannerQueryOptions = new SpannerQueryOptions().setLimit(2).setOffset(3);
List<Trade> trades = this.spannerTemplate.query(Trade.class, Statement.of("SELECT * FROM trades"), spannerQueryOptions);

请注意,以上相当于跑步。​​SELECT * FROM trades LIMIT 2 OFFSET 3​

排序

按键读取不支持排序。 但是,对模板 API 的查询支持通过标准 SQL 和 Spring 数据排序 API 进行排序:

List<Trade> trades = this.spannerTemplate.queryAll(Trade.class, Sort.by("action"));

如果提供的排序字段名称是域类型的属性的名称,则将在查询中使用与该属性对应的列名称。 否则,假定给定的字段名称是云扳手表中列的名称。 可以对云扳手类型的 STRING 和 BYTES 的列进行排序,同时忽略大小写:

Sort.by(Order.desc("action").ignoreCase())

部分读取

Partial read is only possible when using Queries. In case the rows returned by the query have fewer columns than the entity that it will be mapped to, Spring Data will map the returned columns only. This setting also applies to nested structs and their corresponding nested POJO properties.

List<Trade> trades = this.spannerTemplate.query(Trade.class, Statement.of("SELECT action, symbol FROM trades"),
new SpannerQueryOptions().setAllowMissingResultSetColumns(true));

If the setting is set to , then an exception will be thrown if there are missing columns in the query result.​​false​

Summary of options for Query vs Read

Feature

Query supports it

Read supports it

SQL

yes

no

Partial read

yes

no

Limits

yes

no

Offsets

yes

no

Secondary index

yes

yes

使用索引范围读取

是的

排序

是的

13.3.4. 写入/更新

的写入方法接受 POJO 并将其所有属性写入 Spanner。 相应的 Spanner 表和实体元数据是从给定对象的实际类型中获取的。​​SpannerOperations​

如果从 Spanner 检索 POJO,并且其主键属性值已更改,然后写入或更新,则操作将像针对具有新主键值的行一样发生。 具有原始主键值的行将不受影响。

插入

该方法接受 POJO 并将其所有属性写入 Spanner,这意味着如果表中已存在具有 POJO 主键的行,则操作将失败。​​insert​​​​SpannerOperations​

Trade t = new Trade();
this.spannerTemplate.insert(t);

更新

该方法接受 POJO 并将其所有属性写入 Spanner,这意味着如果表中尚不存在 POJO 的主键,则操作将失败。​​update​​​​SpannerOperations​

// t was retrieved from a previous operation
this.spannerTemplate.update(t);

更新插入

该方法接受 POJO 并使用更新或插入将其所有属性写入 Spanner。​​upsert​​​​SpannerOperations​

// t was retrieved from a previous operation or it's new
this.spannerTemplate.upsert(t);

部分更新

的更新方法默认对给定对象中的所有属性进行操作,但也对列名进行操作。 如果列名集为空,则所有列都将写入 Spanner。 但是,如果 Optional 被空集占用,则不会写入任何列。​​SpannerOperations​​​​String[]​​​​Optional<Set<String>>​​​​Optional​

// t was retrieved from a previous operation or it's new
this.spannerTemplate.update(t, "symbol", "action");

13.3.5. DML

可以使用 DML 语句运行。 插入、更新和删除可能会影响任意数量的行和实体。​​SpannerOperations.executeDmlStatement​

可以使用该方法运行分区的 DML更新。 分区 DML 查询具有性能优势,但也具有限制,不能在事务中使用。​​executePartitionedDmlStatement​

13.3.6. 交易

​SpannerOperations​​提供在单个事务中运行对象的方法,同时提供从中读取和写入方法。​​java.util.Function​​​​SpannerOperations​

读/写事务

读取和写入事务通过以下方式提供:​​SpannerOperations​​​​performReadWriteTransaction​

@Autowired
SpannerOperations mySpannerOperations;

public String doWorkInsideTransaction() {
return mySpannerOperations.performReadWriteTransaction(
transActionSpannerOperations -> {
// Work with transActionSpannerOperations here.
// It is also a SpannerOperations object.

return "transaction completed";
}
);
}

该方法接受a,它提供了一个对象的实例。 函数的最终返回值和类型由用户确定。 您可以像使用常规对象一样使用此对象,但有一些例外:​​performReadWriteTransaction​​​​Function​​​​SpannerOperations​​​​SpannerOperations​

  • 它的读取功能无法执行过时的读取,因为所有读取和写入都发生在事务的单个时间点。
  • 它不能通过 执行子事务。performReadWriteTransactionperformReadOnlyTransaction

由于这些读写事务是锁定的,因此建议您使用if函数不执行任何写入。​​performReadOnlyTransaction​

只读事务

该方法用于使用以下方法执行只读事务:​​performReadOnlyTransaction​​​​SpannerOperations​

@Autowired
SpannerOperations mySpannerOperations;

public String doWorkInsideTransaction() {
return mySpannerOperations.performReadOnlyTransaction(
transActionSpannerOperations -> {
// Work with transActionSpannerOperations here.
// It is also a SpannerOperations object.

return "transaction completed";
}
);
}

该方法接受a,它提供了一个对象的实例。 此方法也接受对象,但唯一使用的属性是用于确定快照以在事务中执行读取的时间时间戳。 如果未在读取选项中设置时间戳,则事务将针对数据库的当前状态运行。 函数的最终返回值和类型由用户确定。 您可以像使用常规对象一样使用此对象 一些例外:​​performReadOnlyTransaction​​​​Function​​​​SpannerOperations​​​​ReadOptions​​​​SpannerOperations​

  • 它的读取功能无法执行过时读取(除了对整个事务设置的过期时间),因为所有读取都发生在事务的单个时间点。
  • 它不能通过以下方式执行子事务performReadWriteTransactionperformReadOnlyTransaction
  • 它不能执行任何写入操作。

由于只读事务是非锁定的,并且可以在过去的时间点上执行,因此建议对不执行写入操作的函数执行这些事务。

带有@Transactional注释的声明性事务

此功能需要 bean,这是在使用时提供的。​​SpannerTransactionManager​​​​spring-cloud-gcp-starter-data-spanner​

​SpannerTemplate​​并支持将注释作为事务运行方法。 如果一个方法被注释了调用另一个也带注释的方法,则这两个方法将在同一事务中工作。并且不能在注释方法中使用,因为 Cloud Spanner 不支持事务中的事务。​​SpannerRepository​​​​@Transactional​​​​@Transactional​​​​performReadOnlyTransaction​​​​performReadWriteTransaction​​​​@Transactional​

13.3.7. DML 语句

​SpannerTemplate​​支持DML。 DML 语句也可以通过使用或使用注释在事务中运行。​​Statements​​​​performReadWriteTransaction​​​​@Transactional​

13.4. 仓库

Spring 数据存储库是一个强大的抽象,可以为您节省大量样板代码。

例如:

public interface TraderRepository extends SpannerRepository<Trader, String> {
}

Spring Data 生成指定接口的工作实现,可以方便地自动连接到应用程序中。

类型参数引用基础域类型。 在这种情况下,第二个类型参数是指域类型的键的类型。​​Trader​​​​SpannerRepository​​​​String​

对于具有复合主键的 POJO,此 ID 类型参数可以是与所有主键属性兼容的任何后代、或的任何后代。 如果域 POJO 类型只有一个主键列,则可以使用主键属性类型或类型。​​Object[]​​​​Iterable​​​​com.google.cloud.spanner.Key​​​​Key​

例如,在属于交易者的交易的情况下,如下所示:​​TradeRepository​

public interface TradeRepository extends SpannerRepository<Trade, String[]> {

}

public class MyApplication {

@Autowired
SpannerTemplate spannerTemplate;

@Autowired
StudentRepository studentRepository;

public void demo() {

this.tradeRepository.deleteAll();
String traderId = "demo_trader";
Trade t = new Trade();
t.symbol = stock;
t.action = action;
t.traderId = traderId;
t.price = new BigDecimal("100.0");
t.shares = 12345.6;
this.spannerTemplate.insert(t);

Iterable<Trade> allTrades = this.tradeRepository.findAll();

int count = this.tradeRepository.countByAction("BUY");

}
}

13.4.1. CRUD 存储库

​CrudRepository​​方法按预期工作,Spanner 特定于一件事:和方法作为更新或插入工作。​​save​​​​saveAll​

13.4.2. 分页和排序存储库

您还可以与扳手弹簧数据一起使用。 此接口提供的排序和可分页方法对 Spanner 数据库的当前状态进行操作。 因此,请注意,在逐页移动时,数据库的状态(和结果)可能会更改。​​PagingAndSortingRepository​​​​findAll​

13.4.3. 扳手存储库

扩展,但添加了 Spanner 提供的只读和读写事务功能。 这些事务的工作方式与存储库的事务非常相似,但特定于存储库的域类型,并提供存储库功能而不是模板功能。​​SpannerRepository​​​​PagingAndSortingRepository​​​​SpannerOperations​

例如,这是一个只读事务:

@Autowired
SpannerRepository myRepo;

public String doWorkInsideTransaction() {
return myRepo.performReadOnlyTransaction(
transactionSpannerRepo -> {
// Work with the single-transaction transactionSpannerRepo here.
// This is a SpannerRepository object.

return "transaction completed";
}
);
}

在为您自己的域类型和查询方法创建自定义存储库时,您可以扩展以访问特定于 Cloud Spanner 的功能以及来自 and 的所有功能。​​SpannerRepository​​​​PagingAndSortingRepository​​​​CrudRepository​

13.5. 查询方法

​SpannerRepository​​支持查询方法。 如以下各节所述,这些方法是驻留在自定义存储库接口中的方法,这些方法根据其名称和注释生成实现。 查询方法可以在 Cloud Spanner 中读取、写入和删除实体。 这些方法的参数可以是直接支持的任何 Cloud Spanner 数据类型,也可以是直接支持的任何 Cloud Spanner 数据类型,也可以是通过自定义配置的转换器支持的。 参数也可以是类型或 POJO。 如果将 POJO 作为参数给出,则它将被转换为具有与用于创建写入突变相同的类型转换逻辑的 a。 使用结构参数的比较仅限于Cloud Spanner可用的比较。StructStruct

13.5.1. 按约定查询方法

public interface TradeRepository extends SpannerRepository<Trade, String[]> {
List<Trade> findByAction(String action);

int countByAction(String action);

// Named methods are powerful, but can get unwieldy
List<Trade> findTop3DistinctByActionAndSymbolIgnoreCaseOrTraderIdOrderBySymbolDesc(
String action, String symbol, String traderId);
}

在上面的示例中,查询方法是使用Spring 数据查询创建命名约定根据方法的名称生成的。​​TradeRepository​

​List<Trade> findByAction(String action)​​将转换为 a。​​SELECT * FROM trades WHERE action = ?​

该函数将被翻译为等效于此 SQL 查询:​​List<Trade> findTop3DistinctByActionAndSymbolIgnoreCaseOrTraderIdOrderBySymbolDesc(String action, String symbol, String traderId);​

SELECT DISTINCT * FROM trades
WHERE ACTION = ? AND LOWER(SYMBOL) = LOWER(?) AND TRADER_ID = ?
ORDER BY SYMBOL DESC
LIMIT 3

支持以下筛选器选项:

  • 平等
  • 大于或等于
  • 大于
  • 小于或等于
  • 小于
  • 为空
  • 不为空
  • 是真的
  • 是假的
  • 像一根绳子
  • 不像字符串
  • 包含一个字符串
  • 不包含字符串
  • 不在

请注意,该短语被翻译为表示不区分大小写的匹配。 短语只能附加到与字符串或字节类型的列对应的字段。 不支持追加在方法名称末尾的 Spring 数据“AllIgnoreCase”短语。​​SymbolIgnoreCase​​​​LOWER(SYMBOL) = LOWER(?)​​​​IgnoreCase​

理论命名约定:​​Like​​​​NotLike​

List<Trade> findBySymbolLike(String symbolFragment);

参数可以包含用于字符串匹配的通配符,例如 and。​​symbolFragment​​​​_​​​​%​

命名约定:​​Contains​​​​NotContains​

List<Trade> findBySymbolContains(String symbolFragment);

paramis 检查出现次数的正则表达式。​​symbolFragment​

Theand关键字必须与相应的参数一起使用。​​In​​​​NotIn​​​​Iterable​

还支持删除查询。 例如,查询方法如 或删除 找到的实体。 删除操作发生在单个事务中。​​deleteByAction​​​​removeByAction​​​​findByAction​

删除查询可以具有以下返回类型: * 整数类型,表示删除的实体数 * 已删除的实体的集合 *​​void​

13.5.2. 自定义 SQL/DML 查询方法

上面的示例与Spring 数据查询创建命名约定不匹配,因此我们必须将参数化的 Spanner SQL 查询映射到它。​​List<Trade> fetchByActionNamedQuery(String action)​

可以通过以下两种方式之一将该方法的 SQL 查询映射到存储库方法:

  • ​namedQueries​​属性文件
  • 使用注释@Query

SQL 的标记名称对应于方法参数的注释名称。​​@Param​

交错属性将急切加载,除非它们被批注。​​@Interleaved(lazy = true)​

自定义 SQL 查询方法可以接受应用于指定自定义查询之上的单个或参数。 这是控制结果排序顺序的推荐方法,SQL 查询中的子句无法保证这一点。 这是因为用户提供的查询用作子查询,并且 Cloud Spanner 不会保留子查询结果中的顺序。​​Sort​​​​Pageable​​​​ORDER BY​

您可能希望使用with根据指定的顺序获取排名靠前的记录。 但是,为了确保最终结果集的正确排序顺序,排序选项必须使用 a 传入。​​ORDER BY​​​​LIMIT​​​​Pageable​

@Query("SELECT * FROM trades")
List<Trade> fetchTrades(Pageable pageable);

@Query("SELECT * FROM trades ORDER BY price DESC LIMIT 1")
Trade topTrade(Pageable pageable);

这可用于:

List<Trade> customSortedTrades = tradeRepository.fetchTrades(PageRequest
.of(2, 2, org.springframework.data.domain.Sort.by(Order.asc("id"))));

结果将按“id”升序排序。

查询方法还可以返回非实体类型:

@Query("SELECT COUNT(1) FROM trades WHERE action = @action")
int countByActionQuery(String action);

@Query("SELECT EXISTS(SELECT COUNT(1) FROM trades WHERE action = @action)")
boolean existsByActionQuery(String action);

@Query("SELECT action FROM trades WHERE action = @action LIMIT 1")
String getFirstString(@Param("action") String action);

@Query("SELECT action FROM trades WHERE action = @action")
List<String> getFirstStringList(@Param("action") String action);

DML 语句也可以由查询方法运行,但唯一可能的返回值是表示受影响的行数。 必须将布尔设置设置为 指示查询方法作为 DML 语句运行。​​long​​​​dmlStatement​​​​@Query​

@Query(value = "DELETE FROM trades WHERE action = @action", dmlStatement = true)
long deleteByActionQuery(String action);

具有命名查询属性的查询方法

默认情况下,属性指向文件。 您可以通过提供 SQL 作为“interface.method”属性的值来指定属性文件中方法的查询:​​namedQueriesLocation​​​​@EnableSpannerRepositories​​​​META-INF/spanner-named-queries.properties​

Trade.fetchByActionNamedQuery=SELECT * FROM trades WHERE trades.action = @tag0

public interface TradeRepository extends SpannerRepository<Trade, String[]> {
// This method uses the query from the properties file instead of one generated based on name.
List<Trade> fetchByActionNamedQuery(@Param("tag0") String action);
}

带批注的查询方法

使用注释:​​@Query​

public interface TradeRepository extends SpannerRepository<Trade, String[]> {
@Query("SELECT * FROM trades WHERE trades.action = @tag0")
List<Trade> fetchByActionNamedQuery(@Param("tag0") String action);
}

可以直接使用表名。 例如,上面示例中的“交易”。 或者,也可以从域类上的注释中解析表名。 在这种情况下,查询应引用在字符之间具有完全限定类名的表名:。 一个完整的示例如下所示:​​@Table​​​​:​​​​:fully.qualified.ClassName:​

@Query("SELECT * FROM :com.example.Trade: WHERE trades.action = @tag0")
List<Trade> fetchByActionNamedQuery(String action);

这允许在自定义查询中使用使用 SpEL 评估的表名。

SpEL 还可用于提供 SQL 参数:

@Query("SELECT * FROM :com.example.Trade: WHERE trades.action = @tag0
AND price > #{#priceRadius * -1} AND price < #{#priceRadius * 2}")
List<Trade> fetchByActionNamedQuery(String action, Double priceRadius);

使用 SQL 子句时,请记住使用 指定单个参数。 您还可以使用固定数量的奇异参数,例如。​​IN​​​​IN UNNEST(@iterableParam)​​​​Iterable​​​​IN (@stringParam1, @stringParam2)​

13.5.3. 预测

Spring Data Spanner 支持投影。 您可以根据域类型定义投影接口,并添加在存储库中返回它们的查询方法:

public interface TradeProjection {

String getAction();

@Value("#{target.symbol + ' ' + target.action}")
String getSymbolAndAction();
}

public interface TradeRepository extends SpannerRepository<Trade, Key> {

List<Trade> findByTraderId(String traderId);

List<TradeProjection> findByAction(String action);

@Query("SELECT action, symbol FROM trades WHERE action = @action")
List<TradeProjection> findByQuery(String action);
}

投影可以由基于名称约定的查询方法以及自定义 SQL 查询提供。 如果使用自定义 SQL 查询,则可以进一步将从 Spanner 检索的列限制为投影所需的列以提高性能。

使用 SpEL 定义的投影类型的属性使用基础域对象的固定名称。 因此,访问基础属性采用以下形式。​​target​​​​target.<property-name>​

13.5.4. 仓库方法中的空结果处理

Java 可用于指示可能缺少返回值。​​java.util.Optional​

或者,查询方法可以在没有包装器的情况下返回结果。 在这种情况下,通过返回来指示缺少查询结果。 存储库方法保证永远不会返回集合,而是返回相应的空集合。​​null​​​​null​

您可以启用可空性检查。有关更多详细信息,请参阅Spring 框架的可空性文档。

13.5.5. REST 仓库

使用 Spring 引导运行时,只需将此依赖项添加到您的 pom 文件中,就可以将存储库作为 REST 服务公开:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

如果您希望配置参数(例如路径),则可以使用注释:​​@RepositoryRestResource​

@RepositoryRestResource(collectionResourceRel = "trades", path = "trades")
public interface TradeRepository extends SpannerRepository<Trade, Key> {
}

对于具有组合键(多个字段)的类,存储库 ID 类型仅支持该类型。​​@PrimaryKey​​​​Key​

例如,您可以使用或任何特定的交易方式检索存储库中的所有对象。​​Trade​​​​curl http://<server>:<port>/trades​​​​curl http://<server>:<port>/trades/<trader_id>,<trade_id>​

主键组件之间的分隔符,在本例中,默认情况下是逗号,但可以通过扩展类配置为键值中找不到的任何字符串:​​id​​​​trader_id​​​​SpannerKeyIdConverter​

@Component
class MySpecialIdConverter extends SpannerKeyIdConverter {

@Override
protected String getUrlIdSeparator() {
return ":";
}
}

您还可以使用文件保存对象的 JSON 表示形式来编写交易。​​curl -XPOST -H"Content-Type: application/json" -d@test.json http://<server>:<port>/trades/​​​​test.json​​​​Trade​

13.6. 数据库和模式管理

Spanner 实例中的数据库和表可以从对象自动创建:​​SpannerPersistentEntity​

@Autowired
private SpannerSchemaUtils spannerSchemaUtils;

@Autowired
private SpannerDatabaseAdminTemplate spannerDatabaseAdminTemplate;

public void createTable(SpannerPersistentEntity entity) {
if(!spannerDatabaseAdminTemplate.tableExists(entity.tableName()){

// The boolean parameter indicates that the database will be created if it does not exist.
spannerDatabaseAdminTemplate.executeDdlStrings(Arrays.asList(
spannerSchemaUtils.getCreateTableDDLString(entity.getType())), true);
}
}

可以为具有交错关系和组合键的整个对象层次结构生成架构。

13.7. 事件

Spring Data Cloud Spanner 发布事件,将 Spring 框架扩展到您注册的 bean 可以接收的上下文。​​ApplicationEvent​​​​ApplicationListener​

类型

描述

内容

​AfterReadEvent​

在通过 Cloud Spanner 的密钥读取实体后立即发布​​SpannerTemplate​

加载的实体。最初为装入操作指定的读取选项和密钥集。

​AfterQueryEvent​

在通过 Cloud Spanner 的查询读取实体后立即发布​​SpannerTemplate​

加载的实体。最初为装入操作指定的查询选项和查询语句。

​BeforeExecuteDmlEvent​

在执行 DML 语句之前立即发布​​SpannerTemplate​

要执行的 DML 语句。

​AfterExecuteDmlEvent​

在执行 DML 语句后立即发布​​SpannerTemplate​

要执行的 DML 语句以及受 Cloud Spanner 报告的操作影响的行数。

​BeforeSaveEvent​

在执行更新/更新/插入操作之前立即发布​​SpannerTemplate​

要发送到 Cloud Spanner 的突变、要保存的实体以及要保存的这些实体中的属性(可选)。

​AfterSaveEvent​

在执行更新/更新/插入操作后立即发布​​SpannerTemplate​

发送到 Cloud Spanner 的突变、要保存的实体以及这些实体中要保存的属性(可选)。

​BeforeDeleteEvent​

在执行删除操作之前立即发布​​SpannerTemplate​

要发送到Cloud Spanner的突变。最初为删除操作指定的目标实体、键或实体类型。

​AfterDeleteEvent​

在执行删除操作后立即发布​​SpannerTemplate​

发送到Cloud Spanner的突变。最初为删除操作指定的目标实体、键或实体类型。

13.8. 审计

Spring Data Cloud Spanner 支持属性的注释和审核:​​@LastModifiedDate​​​​@LastModifiedBy​

@Table
public class SimpleEntity {
@PrimaryKey
String id;

@LastModifiedBy
String lastUser;

@LastModifiedDate
DateTime lastTouched;
}

插入、更新或保存后,这些属性将由框架自动设置,然后再生成突变并将其保存到 Cloud Spanner。

要利用这些功能,请将注释添加到配置类中,并为实现提供一个 Bean,其中类型是所需的属性类型,由以下人员注释:​​@EnableSpannerAuditing​​​​AuditorAware<A>​​​​A​​​​@LastModifiedBy​

@Configuration
@EnableSpannerAuditing
public class Config {

@Bean
public AuditorAware<String> auditorProvider() {
return () -> Optional.of("YOUR_USERNAME_HERE");
}
}

该接口包含单个方法,该方法为批注的字段提供值,并且可以是任何类型。 一种替代方法是使用 Spring Security 的类型:​​AuditorAware​​​​@LastModifiedBy​​​​User​

class SpringSecurityAuditorAware implements AuditorAware<User> {

public Optional<User> getCurrentAuditor() {

return Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getPrincipal)
.map(User.class::cast);
}
}

您还可以通过提供 Bean forand 提供 Bean 名称来为批注的属性设置自定义提供程序。​​@LastModifiedDate​​​​DateTimeProvider​​​​@EnableSpannerAuditing(dateTimeProviderRef = "customDateTimeProviderBean")​

13.9. 多实例使用

通过为其提供自定义 Bean,可以将应用程序配置为使用多个 Cloud Spanner 实例或数据库。 缺省 Bean 使用您在其中配置的实例标识、数据库名称和项目标识选项。​​DatabaseIdProvider​​​​application.properties​

@Bean
public DatabaseIdProvider databaseIdProvider() {
// return custom connection options provider
}

由此提供程序给出的用作 Spring 数据云扳手执行的每个操作的目标数据库名称和实例。 通过提供此 Bean 的定制实现(例如,提供线程本地),您可以指示应用程序使用多个实例或数据库。​​DatabaseId​​​​DatabaseId​

数据库管理操作(例如使用创建表)也将利用所提供的。​​SpannerDatabaseAdminTemplate​​​​DatabaseId​

如果要配置每个连接的各个方面(例如池大小和重试设置),则可以为其提供 bean。​​Supplier<DatabaseClient>​

13.10. 弹簧启动执行器支持

13.10.1. 云扳手健康指示器

如果您使用的是 Spring 启动执行器,则可以利用调用的云扳手健康指示器。 运行状况指示器将验证 Cloud Spanner 是否已启动并可供应用程序访问。 要启用它,您需要做的就是将Spring 启动执行器添加到您的项目中。​​spanner​

然后,指示器将汇总到​​在 localhost:8080/actuator/health​​ (使用该属性查看每个指示器的详细信息)可见的整体应用程序状态。​​spanner​​​​management.endpoint.health.show-details​

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

如果您的应用程序已有执行器和云扳手启动器,则默认情况下启用此运行状况指示器。 要禁用云扳手指示器,请设置为。​​management.health.spanner.enabled​​​​false​

运行状况指示器通过执行查询来验证与 Spanner 的连接。 可以通过属性配置要验证的查询。​​spring.cloud.gcp.spanner.health.query​

名字

描述

必填

默认值

​management.health.spanner.enabled​

是否启用扳手运行状况指示器

​true​​​带弹簧启动执行器,否则​​false​

​spring.cloud.gcp.spanner.health.query​

要验证的查询

​SELECT 1​

13.11. 云扳手模拟器

Cloud SDK为 Cloud Spanner 提供了一个本地内存中模拟器,可用于开发和测试应用程序。由于模拟器仅将数据存储在内存中,因此它不会在运行之间保留数据。它旨在帮助您将 Cloud Spanner 用于本地开发和测试,而不是用于生产部署。

为了设置和启动模拟器,您可以按照以下步骤操作。

此命令可用于创建云扳手实例:

$ gcloud spanner instances create <instance-name> --config=emulator-config --description="<description>" --nodes=1

运行 Spanner 模拟器后,请确保在 Spring 应用程序中设置了以下属性:​​application.properties​

spring.cloud.gcp.spanner.emulator.enabled=true

请注意,使用默认模拟器主机名和端口(即 localhost:9010)。如果您更喜欢自定义值,请确保在 Spring 应用程序中设置以下属性:​​application.properties​

spring.cloud.gcp.spanner.emulator-host=ip:port

13.12. 示例

有两个示例应用程序可用:

  1. 直接使用扳手模板的示例应用程序
  2. 使用更高级别的扳手存储库功能的示例应用程序

13.13. 测试

​Testcontainers​​提供模块。在文档中查看更多信息​​gcloud​​​​SpannerEmulatorContainer​

举报

相关推荐

0 条评论