Spring 引导应用程序中的复合 Cassandra 键
Composite Cassandra Key in Spring Boot Application
我有一个使用以下方法创建的 Cassandra 集群:
CREATE KEYSPACE IF NOT EXISTS activitylogs WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
CREATE TABLE IF NOT EXISTS activitylogs.activities (
activity_id timeuuid,
actor_id text,
app_id text,
item_id text,
viewer_id text,
activity_type int,
ts timestamp,
PRIMARY KEY (actor_id, activity_id, app_id)
) WITH CLUSTERING ORDER BY (activity_id DESC, app_id ASC);
INSERT INTO activities (activity_id,actor_id, app_id, item_id, viewer_id, activity_type) VALUES ( now(), 'fsdgs346-sdsd5-4242','blossom','ff235-fsd54-fadsfdfs45','hj923hjn-2jnkl23-323yfh',0);
我将 Eclipse 与以下 build.gradle 一起使用:
group 'com.abc'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE")
}
}
jar {
baseName = 'gs-serving-web-content'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.data:spring-data-cassandra:1.4.6.RELEASE"
compile 'org.slf4j:slf4j-api:1.6.6'
compile 'ch.qos.logback:logback-classic:1.0.13'
testCompile "junit:junit"
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
现在,我编写了以下实体:
package com.abc.activitystream.entity;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import java.security.Timestamp;
@Table(value = "activities")
public class Activity
{
/*CREATE TABLE IF NOT EXISTS activitylogs.activities (
activity_id timeuuid,
actor_id text,
app_id text,
item_id text,
viewer_id text,
activity_type int,
ts timestamp,
PRIMARY KEY (actor_id, activity_id, app_id)) WITH CLUSTERING ORDER BY (activity_id DESC);*/
@PrimaryKey
private ActivityKey ak;
@Column(value = "item_id")
private String item_id;
@Column(value = "viewer_id")
private String viewer_id;
@Column(value = "activity_type")
private int activity_type;
@Column(value = "ts")
private Timestamp ts;
public String getItem_id() {
return item_id;
}
public void setItem_id(String item_id) {
this.item_id = item_id;
}
public String getViewer_id() {
return viewer_id;
}
public void setViewer_id(String viewer_id) {
this.viewer_id = viewer_id;
}
public int getActivity_type() {
return activity_type;
}
public void setActivity_type(int activity_type) {
this.activity_type = activity_type;
}
public Timestamp getTs() {
return ts;
}
public void setTs(Timestamp ts) {
this.ts = ts;
}
public ActivityKey getAk() {
return ak;
}
public void setAk(ActivityKey ak) {
this.ak = ak;
}
}
因为 table 使用复合主键,我不得不使用这里提到的以下结构:http://docs.spring.io/spring-data/cassandra/docs/1.0.2.RELEASE/reference/html/cassandra.core.html
所以我的 ActivityKey class 是这样的:
@PrimaryKeyClass
public class ActivityKey implements Serializable {
@PrimaryKeyColumn(name = "actor_id",ordinal = 0,type = PrimaryKeyType.PARTITIONED)
private String actor_id;
@PrimaryKeyColumn(name="activity_id",ordinal = 1,type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING )
private UUID activity_id = UUIDs.timeBased();
@PrimaryKeyColumn(name="app_id", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING)
private String app_id;
public String getActor_id() {
return actor_id;
}
public void setActor_id(String actor_id) {
this.actor_id = actor_id;
}
public UUID getActivity_id() {
return activity_id;
}
public void setActivity_id(UUID activity_id) {
this.activity_id = activity_id;
}
public String getApp_id() {
return app_id;
}
public void setApp_id(String app_id) {
this.app_id = app_id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((actor_id == null) ? 0 : actor_id.hashCode());
result = prime * result + ((app_id == null) ? 0 : app_id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ActivityKey other = (ActivityKey) obj;
if (actor_id == null) {
if (other.actor_id != null)
return false;
} else if (!actor_id.equals(other.actor_id))
return false;
if (app_id == null) {
if (other.app_id != null)
return false;
} else if (!app_id.equals(other.app_id))
return false;
return true;
}
}
我的控制器是这样的:
@RestController
public class ActivityController {
@Autowired
private ActivityRepository activityRepository;
@RequestMapping(value = "/activity",method = RequestMethod.GET)
@ResponseBody
public List<Activity> activity() {
List<Activity> activities = new ArrayList<>();
activityRepository.findAll().forEach(e->activities.add(e));
return activities;
}
}
最终存储库是这样的:
public interface ActivityRepository extends CassandraRepository<Activity> {
@Query("SELECT*FROM activities WHERE actor_id=?0 LIMIT ?1")
Iterable<Activity> findByActor_Id(String actor_id,Integer limit);
}
奇怪的是,应用程序没有 运行 并退出并出现以下错误:
创建名称为 'greetingController' 的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:private com.rg.cassandraspring.repository.ActivityRepository com.rg.cassandraspring.controller.GreetingController.activityRepository;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名称为 'activityRepository' 的 bean 时出错:调用 init 方法失败;嵌套异常是 org.springframework.data.cassandra.mapping.VerifierMappingExceptions: java.security.cert.CertPath:
Cassandra 实体必须具有@Table、@Persistent 或@PrimaryKeyClass Annotation
最后这是我的 CassandraConfig:
@Configuration
//@PropertySource(value = {"classpath:META-INF/cassandra.properties"})
@EnableCassandraRepositories(basePackages = {"com.abc"})
public class CassandraConfig {
@Autowired
private Environment environment;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class);
@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints("localhost");
cluster.setPort(Integer.parseInt("9042"));
return cluster;
}
@Bean
public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}
@Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
@Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setKeyspaceName("activitylogs");
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
@Bean
public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
有人可以帮我吗?我似乎无法解决这个问题。
问题似乎属于 'Timestamp' 类型,代表 table 'activities' 的 'ts' 列。我将其从 java.util 更改为 'Date',一切似乎 运行 都很好。
不过我还没来得及调查原因。
与您的问题不完全相关,spring 文档指出,当您想在实体中存储时间对象时,您应该使用:
- 乔达时间:日期时间
- 旧版 Java 日期和日历
- JDK8 日期和时间类型
- 长或长
更多信息在这里:https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#auditing.annotations
我有一个使用以下方法创建的 Cassandra 集群:
CREATE KEYSPACE IF NOT EXISTS activitylogs WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true;
CREATE TABLE IF NOT EXISTS activitylogs.activities (
activity_id timeuuid,
actor_id text,
app_id text,
item_id text,
viewer_id text,
activity_type int,
ts timestamp,
PRIMARY KEY (actor_id, activity_id, app_id)
) WITH CLUSTERING ORDER BY (activity_id DESC, app_id ASC);
INSERT INTO activities (activity_id,actor_id, app_id, item_id, viewer_id, activity_type) VALUES ( now(), 'fsdgs346-sdsd5-4242','blossom','ff235-fsd54-fadsfdfs45','hj923hjn-2jnkl23-323yfh',0);
我将 Eclipse 与以下 build.gradle 一起使用:
group 'com.abc'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE")
}
}
jar {
baseName = 'gs-serving-web-content'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile "org.springframework.boot:spring-boot-starter-web"
compile "org.springframework.data:spring-data-cassandra:1.4.6.RELEASE"
compile 'org.slf4j:slf4j-api:1.6.6'
compile 'ch.qos.logback:logback-classic:1.0.13'
testCompile "junit:junit"
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
现在,我编写了以下实体:
package com.abc.activitystream.entity;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKey;
import org.springframework.data.cassandra.mapping.Table;
import java.security.Timestamp;
@Table(value = "activities")
public class Activity
{
/*CREATE TABLE IF NOT EXISTS activitylogs.activities (
activity_id timeuuid,
actor_id text,
app_id text,
item_id text,
viewer_id text,
activity_type int,
ts timestamp,
PRIMARY KEY (actor_id, activity_id, app_id)) WITH CLUSTERING ORDER BY (activity_id DESC);*/
@PrimaryKey
private ActivityKey ak;
@Column(value = "item_id")
private String item_id;
@Column(value = "viewer_id")
private String viewer_id;
@Column(value = "activity_type")
private int activity_type;
@Column(value = "ts")
private Timestamp ts;
public String getItem_id() {
return item_id;
}
public void setItem_id(String item_id) {
this.item_id = item_id;
}
public String getViewer_id() {
return viewer_id;
}
public void setViewer_id(String viewer_id) {
this.viewer_id = viewer_id;
}
public int getActivity_type() {
return activity_type;
}
public void setActivity_type(int activity_type) {
this.activity_type = activity_type;
}
public Timestamp getTs() {
return ts;
}
public void setTs(Timestamp ts) {
this.ts = ts;
}
public ActivityKey getAk() {
return ak;
}
public void setAk(ActivityKey ak) {
this.ak = ak;
}
}
因为 table 使用复合主键,我不得不使用这里提到的以下结构:http://docs.spring.io/spring-data/cassandra/docs/1.0.2.RELEASE/reference/html/cassandra.core.html
所以我的 ActivityKey class 是这样的:
@PrimaryKeyClass
public class ActivityKey implements Serializable {
@PrimaryKeyColumn(name = "actor_id",ordinal = 0,type = PrimaryKeyType.PARTITIONED)
private String actor_id;
@PrimaryKeyColumn(name="activity_id",ordinal = 1,type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING )
private UUID activity_id = UUIDs.timeBased();
@PrimaryKeyColumn(name="app_id", ordinal = 2, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.ASCENDING)
private String app_id;
public String getActor_id() {
return actor_id;
}
public void setActor_id(String actor_id) {
this.actor_id = actor_id;
}
public UUID getActivity_id() {
return activity_id;
}
public void setActivity_id(UUID activity_id) {
this.activity_id = activity_id;
}
public String getApp_id() {
return app_id;
}
public void setApp_id(String app_id) {
this.app_id = app_id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((actor_id == null) ? 0 : actor_id.hashCode());
result = prime * result + ((app_id == null) ? 0 : app_id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ActivityKey other = (ActivityKey) obj;
if (actor_id == null) {
if (other.actor_id != null)
return false;
} else if (!actor_id.equals(other.actor_id))
return false;
if (app_id == null) {
if (other.app_id != null)
return false;
} else if (!app_id.equals(other.app_id))
return false;
return true;
}
}
我的控制器是这样的:
@RestController
public class ActivityController {
@Autowired
private ActivityRepository activityRepository;
@RequestMapping(value = "/activity",method = RequestMethod.GET)
@ResponseBody
public List<Activity> activity() {
List<Activity> activities = new ArrayList<>();
activityRepository.findAll().forEach(e->activities.add(e));
return activities;
}
}
最终存储库是这样的:
public interface ActivityRepository extends CassandraRepository<Activity> {
@Query("SELECT*FROM activities WHERE actor_id=?0 LIMIT ?1")
Iterable<Activity> findByActor_Id(String actor_id,Integer limit);
}
奇怪的是,应用程序没有 运行 并退出并出现以下错误:
创建名称为 'greetingController' 的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:private com.rg.cassandraspring.repository.ActivityRepository com.rg.cassandraspring.controller.GreetingController.activityRepository;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名称为 'activityRepository' 的 bean 时出错:调用 init 方法失败;嵌套异常是 org.springframework.data.cassandra.mapping.VerifierMappingExceptions: java.security.cert.CertPath: Cassandra 实体必须具有@Table、@Persistent 或@PrimaryKeyClass Annotation
最后这是我的 CassandraConfig:
@Configuration
//@PropertySource(value = {"classpath:META-INF/cassandra.properties"})
@EnableCassandraRepositories(basePackages = {"com.abc"})
public class CassandraConfig {
@Autowired
private Environment environment;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class);
@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints("localhost");
cluster.setPort(Integer.parseInt("9042"));
return cluster;
}
@Bean
public CassandraMappingContext mappingContext() {
return new BasicCassandraMappingContext();
}
@Bean
public CassandraConverter converter() {
return new MappingCassandraConverter(mappingContext());
}
@Bean
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setKeyspaceName("activitylogs");
session.setConverter(converter());
session.setSchemaAction(SchemaAction.NONE);
return session;
}
@Bean
public CassandraOperations cassandraTemplate() throws Exception {
return new CassandraTemplate(session().getObject());
}
}
有人可以帮我吗?我似乎无法解决这个问题。
问题似乎属于 'Timestamp' 类型,代表 table 'activities' 的 'ts' 列。我将其从 java.util 更改为 'Date',一切似乎 运行 都很好。
不过我还没来得及调查原因。
与您的问题不完全相关,spring 文档指出,当您想在实体中存储时间对象时,您应该使用:
- 乔达时间:日期时间
- 旧版 Java 日期和日历
- JDK8 日期和时间类型
- 长或长
更多信息在这里:https://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#auditing.annotations