Spring Data Cassandra是否支持同一应用程序上下文中的多个键空间存储库?我正在使用以下JavaConfig类
设置cassandra spring数据配置@Configuration
@EnableCassandraRepositories(basePackages = "com.blah.repository")
public class CassandraConfig extends AbstractCassandraConfiguration {
@Override
public String getKeyspaceName() {
return "keyspace1";
}
在将存储库类移动到另一个包之后,我尝试创建第二个配置类。
@Configuration
@EnableCassandraRepositories(basePackages = "com.blah.secondrepository")
public class SecondCassandraConfig extends AbstractCassandraConfiguration {
@Override
public String getKeyspaceName() {
return "keyspace2";
}
但是,在这种情况下,第一个集合是否存储库失败,因为在键空间中找不到实体的已配置列族。我认为它可能正在寻找第二个键空间中的列族。
spring-data-cassandra是否支持多个密钥空间存储库?我找到多个键空间的引用的唯一地方是here。但它没有解释是否可以使用存储库来完成?
答案 0 :(得分:5)
工作APP示例: http://valchkou.com/spring-boot-cassandra.html#multikeyspace
您需要的构思会覆盖默认bean:sessionfactory和template
样品:
1)application.yml
spring:
data:
cassandra:
test1:
keyspace-name: test1_keyspace
contact-points: localhost
test2:
keyspace-name: test2_keyspace
contact-points: localhost
2)基本配置类
public abstract class CassandraBaseConfig extends AbstractCassandraConfiguration{
protected String contactPoints;
protected String keyspaceName;
public String getContactPoints() {
return contactPoints;
}
public void setContactPoints(String contactPoints) {
this.contactPoints = contactPoints;
}
public void setKeyspaceName(String keyspaceName) {
this.keyspaceName = keyspaceName;
}
@Override
protected String getKeyspaceName() {
return keyspaceName;
}
}
3)配置test1的实现
package com.sample.repo.test1;
@Configuration
@ConfigurationProperties("spring.data.cassandra.test1")
@EnableCassandraRepositories(
basePackages = "com.sample.repo.test1",
cassandraTemplateRef = "test1Template"
)
public class Test1Config extends CassandraBaseConfig {
@Override
@Primary
@Bean(name = "test1Template")
public CassandraAdminOperations cassandraTemplate() throws Exception {
return new CassandraAdminTemplate(session().getObject(), cassandraConverter());
}
@Override
@Bean(name = "test1Session")
public CassandraSessionFactoryBean session() throws Exception {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster().getObject());
session.setConverter(cassandraConverter());
session.setKeyspaceName(getKeyspaceName());
session.setSchemaAction(getSchemaAction());
session.setStartupScripts(getStartupScripts());
session.setShutdownScripts(getShutdownScripts());
return session;
}
}
4)同样适用于test2,只需使用不同的包 包com.sample.repo.test2;
5)在专用包中为每个键空间放置repo 即。
package com.sample.repo.test1;
@Repository
public interface RepositoryForTest1 extends CassandraRepository<MyEntity> {
// ....
}
package com.sample.repo.test2;
@Repository
public interface RepositoryForTest2 extends CassandraRepository<MyEntity> {
// ....
}
答案 1 :(得分:2)
尝试为每个键空间显式命名CassandraTemplate
个bean,并在@EnableCassandraRepositories
注释的cassandraTemplateRef
属性中使用这些名称(请参阅/* CHANGED */
行进行更改)。
在您的第一个配置中:
@Configuration
@EnableCassandraRepositories(basePackages = "com.blah.repository",
/* CHANGED */ cassandraTemplateRef = "template1")
public class CassandraConfig extends AbstractCassandraConfiguration {
@Override
public String getKeyspaceName() {
return "keyspace1";
}
/* CHANGED */
@Override
@Bean(name = "template1")
public CassandraAdminOperations cassandraTemplate() throws Exception {
return new CassandraAdminTemplate(session().getObject(), cassandraConverter());
}
...并在您的第二个配置中:
@Configuration
@EnableCassandraRepositories(basePackages = "com.blah.secondrepository",
/* CHANGED */ cassandraTemplateRef = "template2")
public class SecondCassandraConfig extends AbstractCassandraConfiguration {
@Override
public String getKeyspaceName() {
return "keyspace2";
}
/* CHANGED */
@Override
@Bean(name = "template2")
public CassandraAdminOperations cassandraTemplate() throws Exception {
return new CassandraAdminTemplate(session().getObject(), cassandraConverter());
}
我认为这可能会成功。如果没有,请回复。
答案 2 :(得分:0)
似乎建议在由一个会话管理的查询中使用完全限定的键空间名称,因为会话不是非常轻量级。
请参阅参考here
答案 3 :(得分:0)
我试过这种方法。但是,在尝试访问列族2时遇到异常。列族1的操作似乎没问题。
我猜是因为底层的CassandraSessionFactoryBean bean是一个单例。这导致了 未配置的columnfamily columnfamily2
以下是一些提供上下文的日志
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - 返回单例bean'entityManagerFactory'的缓存实例 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - 返回单例bean'session'的缓存实例 DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - 返回单例bean'cluster'的缓存实例
org.springframework.cassandra.support.exception.CassandraInvalidQueryException:unconfigured columnfamily shardgroup;嵌套异常是com.datastax.driver.core.exceptions.InvalidQueryException:unconfigured columnfamily columnfamily2 在org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:116) 在org.springframework.cassandra.config.CassandraCqlSessionFactoryBean.translateExceptionIfPossible(CassandraCqlSessionFactoryBean.java:74)
答案 4 :(得分:0)
嗯。不能通过matthew-adams对答案发表评论。但是,这将重用会话对象,因为AbstractCassandraConfiguration在所有相关的getter上都使用@Bean注释。
在类似的设置中,我最初使用它来覆盖所有的getter,并专门为它们提供不同的bean名称。但由于Spring仍然声称需要豆类的名称。我现在不得不制作一份AbstractCassandraConfiguration副本,没有我可以继承的注释。
确保公开CassandraTemplate,以便在使用时可以从@EnableCassandraRepositories引用它。
我还有一个单独的AbstractClusterConfiguration实现来公开一个常见的CassandraCqlClusterFactoryBean,以便重用底层连接。
编辑: 我想根据bclarance链接的电子邮件线程,我们应该真正尝试重用Session对象。看起来Spring Data Cassandra并没有真正为此做好准备
答案 5 :(得分:0)
就我而言,我有一个Spring Boot应用程序,其中大多数存储库位于一个键空间中,而只有两个存储库位于一个键空间中。我保留了第一个键空间的默认Spring Boot配置,并使用与Spring Boot用于其自动配置的相同配置方法手动配置了第二个键空间。
@Repository
@NoRepositoryBean // This uses a different keyspace than the default, so not auto-creating
public interface SecondKeyspaceTableARepository
extends MapIdCassandraRepository<SecondKeyspaceTableA> {
}
@Repository
@NoRepositoryBean // This uses a different keyspace than the default, so not auto-creating
public interface SecondKeyspaceTableBRepository
extends MapIdCassandraRepository<SecondKeyspaceTableB> {
}
@Configuration
public class SecondKeyspaceCassandraConfig {
public static final String KEYSPACE_NAME = "second_keyspace";
/**
* @see org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration#cassandraSession(CassandraConverter)
*/
@Bean(autowireCandidate = false)
public CassandraSessionFactoryBean secondKeyspaceCassandraSession(
Cluster cluster, Environment environment, CassandraConverter converter) {
CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
session.setCluster(cluster);
session.setConverter(converter);
session.setKeyspaceName(KEYSPACE_NAME);
Binder binder = Binder.get(environment);
binder.bind("spring.data.cassandra.schema-action", SchemaAction.class)
.ifBound(session::setSchemaAction);
return session;
}
/**
* @see org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration#cassandraTemplate(com.datastax.driver.core.Session, CassandraConverter)
*/
@Bean(autowireCandidate = false)
public CassandraTemplate secondKeyspaceCassandraTemplate(
Cluster cluster, Environment environment, CassandraConverter converter) {
return new CassandraTemplate(secondKeyspaceCassandraSession(cluster, environment, converter)
.getObject(), converter);
}
@Bean
public SecondKeyspaceTableARepository cdwEventRepository(
Cluster cluster, Environment environment, CassandraConverter converter) {
return createRepository(CDWEventRepository.class,
secondKeyspaceCassandraTemplate(cluster, environment, converter));
}
@Bean
public SecondKeyspaceTableBTypeRepository dailyCapacityRepository(
Cluster cluster, Environment environment, CassandraConverter converter) {
return createRepository(DailyCapacityRepository.class,
secondKeyspaceCassandraTemplate(cluster, environment, converter));
}
private <T> T createRepository(Class<T> repositoryInterface, CassandraTemplate operations) {
return new CassandraRepositoryFactory(operations).getRepository(repositoryInterface);
}
}