要充分利用 Spring Data for Apache Cassandra 支持中的对象映射功能,您应该使用注释对映射的域对象进行@Table注释。这样做可以让类路径扫描器找到并预处理您的域对象以提取必要的元数据。仅使用带注释的实体来执行模式操作。在最坏的情况下, SchemaAction.RECREATE_DROP_UNUSED操作会删除您的表并丢失数据。以下示例显示了一个简单的域对象:
示例 106. 示例域对象
package com.mycompany.domain;
@Table
public class Person {
@Id
private String id;
@CassandraType(type = Name.VARINT)
private Integer ssn;
private String firstName;
private String lastName;
}
该@Id注解告诉您要使用的卡珊德拉主键哪个属性映射器。复合主键可能需要稍微不同的数据模型。
Cassandra 需要至少一个 CQL 表的分区键字段。一张表可以额外声明一个或多个集群键字段。当您的 CQL 表具有复合主键时,您必须创建一个@PrimaryKeyClass来定义复合主键的结构。在这种情况下,“复合主键”是指一个或多个分区列可选地与一个或多个集群列组合。
主键可以使用任何单一的简单 Cassandra 类型或映射的用户定义类型。不支持集合类型的主键。
一个简单的主键由实体类中的一个分区键字段组成。由于它只有一个字段,我们可以安全地假设它是一个分区键。以下清单显示了在 Cassandra 中定义的 CQL 表,主键为user_id:
示例 107. Cassandra 中定义的 CQL 表
CREATE TABLE user (
user_id text,
firstname text,
lastname text,
PRIMARY KEY (user_id))
;
以下示例显示了一个已注释的 Java 类,使其对应于前面清单中定义的 Cassandra:
示例 108. 带注释的实体
@Table(value = "login_event")
public class LoginEvent {
@PrimaryKey("user_id")
private String userId;
private String firstname;
private String lastname;
// getters and setters omitted
}
复合主键(或复合键)由多个主键字段组成。也就是说,复合主键可以由多个分区键、一个分区键和一个集群键或多个主键字段组成。
复合键可以通过 Spring Data for Apache Cassandra 以两种方式表示:
组合键的最简单形式是具有一个分区键和一个集群键的键。
以下示例显示了一个 CQL 语句来表示表及其组合键:
示例 109.具有复合主键的 CQL 表
CREATE TABLE login_event(
person_id text,
event_code int,
event_time timestamp,
ip_address text,
PRIMARY KEY (person_id, event_code, event_time))
WITH CLUSTERING ORDER BY (event_time DESC)
;
平面复合主键作为平面字段嵌入到实体中。主键字段用 @PrimaryKeyColumn. 选择要求查询包含单个字段的谓词或使用MapId. 以下示例显示了一个具有平面复合主键的类:
示例 110.使用平面复合主键
@Table(value = "login_event")
class LoginEvent {
@PrimaryKeyColumn(name = "person_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String personId;
@PrimaryKeyColumn(name = "event_code", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private int eventCode;
@PrimaryKeyColumn(name = "event_time", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
private LocalDateTime eventTime;
@Column("ip_address")
private String ipAddress;
// getters and setters omitted
}
主键类是映射到实体的多个字段或属性的复合主键类。它被注释@PrimaryKeyClass并应该定义equals和hashCode方法。这些方法的值相等的语义应该与键映射到的数据库类型的数据库相等一致。主键类可以与存储库(作为Id类型)一起使用,并在单个复杂对象中表示实体的身份。以下示例显示了一个复合主键类:
示例 111. 复合主键类
@PrimaryKeyClass
class LoginEventKey implements Serializable {
@PrimaryKeyColumn(name = "person_id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String personId;
@PrimaryKeyColumn(name = "event_code", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private int eventCode;
@PrimaryKeyColumn(name = "event_time", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
private LocalDateTime eventTime;
// other methods omitted
}
以下示例显示了如何使用复合主键:
示例 112.使用复合主键
@Table(value = "login_event")
public class LoginEvent {
@PrimaryKey
private LoginEventKey key;
@Column("ip_address")
private String ipAddress;
// getters and setters omitted
}
嵌入式实体用于在 Java 域模型中设计值对象,其属性被展平到表中。在下面的示例中,您会看到User.name用@Embedded. 这样做的结果是 的所有属性UserName都被折叠到user由 3 列 ( user_id, firstname, lastname)组成的表格中。
嵌入的实体可能只包含简单的属性类型。不可能将嵌入的实体嵌套到另一个嵌入的实体中。
但是,如果firstname和lastname列值实际上null在结果集中,则整个属性name将null根据onEmptyof进行设置@Embedded,null当所有嵌套属性都为 时,该s 对象null。 与此行为相反,USE_EMPTY尝试使用默认构造函数或从结果集中接受可为空参数值的构造函数创建新实例。
Example 113. 嵌入对象的示例代码
public class User {
@PrimaryKey("user_id")
private String userId;
@Embedded(onEmpty = USE_NULL)
UserName name;
}
public class UserName {
private String firstname;
private String lastname;
}
属性是nulliffirstname和lastnameare null。使用onEmpty=USE_EMPTY实例化UserName一个潜在null其属性值。
您可以使用注释的可选prefix元素在实体中多次嵌入值对象@Embedded。此元素表示一个前缀,并附加到嵌入对象中的每个列名称。请注意,如果多个属性呈现为相同的列名称,则属性将相互覆盖。
利用快捷方式@Embedded.Nullable和@Embedded.Emptyfor@Embedded(onEmpty = USE_NULL)和@Embedded(onEmpty = USE_EMPTY)to 减少冗长,同时相应地设置 JSR-305 @javax.annotation.Nonnull。
public class MyEntity {
@Id
Integer id;
@Embedded.Nullable
EmbeddedEntity embeddedEntity;
}
的快捷方式@Embedded(onEmpty = USE_NULL)。
所述MappingCassandraConverter可以使用元数据来驱动对象的映射中的行表卡桑德拉。注释概述如下:
映射元数据基础结构在独立的 spring-data-commons 项目中定义,该项目与技术和数据存储无关。
以下示例显示了更复杂的映射:
示例 114. 映射Person类
@Table("my_person")
public class Person {
@PrimaryKeyClass
public static class Key implements Serializable {
@PrimaryKeyColumn(ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String type;
@PrimaryKeyColumn(ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private String value;
@PrimaryKeyColumn(name = "correlated_type", ordinal = 2, type = PrimaryKeyType.CLUSTERED)
private String correlatedType;
// other getters/setters omitted
}
@PrimaryKey
private Person.Key key;
@CassandraType(type = CassandraType.Name.VARINT)
private Integer ssn;
@Column("f_name")
private String firstName;
@Column
@Indexed
private String lastName;
private Address address;
@CassandraType(type = CassandraType.Name.UDT, userTypeName = "myusertype")
private UdtValue usertype;
private Coordinates coordinates;
@Transient
private Integer accountTotal;
@CassandraType(type = CassandraType.Name.SET, typeArguments = CassandraType.Name.BIGINT)
private Set<Long> timestamps;
private Map<@Indexed String, InetAddress> sessions;
public Person(Integer ssn) {
this.ssn = ssn;
}
public Person.Key getKey() {
return key;
}
// no setter for Id. (getter is only exposed for some unit testing)
public Integer getSsn() {
return ssn;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
// other getters/setters omitted
}
以下示例显示了如何映射 UDT Address:
示例 115. 映射的用户定义类型 Address
@UserDefinedType("address")
public class Address {
@CassandraType(type = CassandraType.Name.VARCHAR)
private String street;
private String city;
private Set<String> zipcodes;
@CassandraType(type = CassandraType.Name.SET, typeArguments = CassandraType.Name.BIGINT)
private List<Long> timestamps;
// other getters/setters omitted
}
使用用户定义的类型需要UserTypeResolver使用映射上下文进行配置。请参阅配置一章对如何配置UserTypeResolver。
以下示例显示了如何映射元组:
示例 116. 映射元组
@Tuple
class Coordinates {
@Element(0)
@CassandraType(type = CassandraType.Name.VARCHAR)
private String description;
@Element(1)
private long longitude;
@Element(2)
private long latitude;
// other getters/setters omitted
}
您可以使用@Indexed或@SASI如果您希望在应用程序启动时创建二级索引来注释特定的实体属性。索引创建为标量类型、用户定义类型和集合类型创建简单的二级索引。
您可以配置 SASI 索引以应用分析器,例如StandardAnalyzer或NonTokenizingAnalyzer(分别使用 @StandardAnalyzed和@NonTokenizingAnalyzed)。
地图类型的区分ENTRY,KEYS以及VALUES指标。索引创建从带注释的元素派生索引类型。以下示例显示了多种创建索引的方法:
示例 117. 地图索引的变体
@Table
class PersonWithIndexes {
@Id
private String key;
@SASI
@StandardAnalyzed
private String names;
@Indexed("indexed_map")
private Map<String, String> entries;
private Map<@Indexed String, String> keys;
private Map<String, @Indexed String> values;
// …
}
所述@Indexed注释可以应用于嵌入式实体或沿与侧单个属性@Embedded注释,在这种情况下,嵌入的所有属性编索引。
会话初始化时的索引创建可能会对应用程序启动产生严重的性能影响。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。