spring-data-cassandra 存储库的多个键空间支持?
Posted
技术标签:
【中文标题】spring-data-cassandra 存储库的多个键空间支持?【英文标题】:Multiple keyspace support for spring-data-cassandra repositories? 【发布时间】:2014-11-04 09:00:27 【问题描述】: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。但它没有解释这是否可以通过存储库完成?
【问题讨论】:
我将此转发给处理大部分存储库编码的工程师,以便为您解答。请坐好。 【参考方案1】:尝试为每个键空间显式命名 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());
我认为这可能会奏效。如果没有请回帖。
【讨论】:
我会试试这个然后回来。 找不到存储库 bean。【参考方案2】:似乎建议在由一个会话管理的查询中使用完全限定的键空间名称,因为会话不是很轻量级。 请参考参考here
【讨论】:
很好的发现。值得注意的是,您的链接示例有 100 个键空间,而这个有 2 个。两个不太轻量的会话可能是可以接受的,其中 100 个会导致问题。【参考方案3】:我尝试了这种方法。但是,我在尝试访问列族 2 时遇到了异常。列族 1 上的操作似乎没问题。
我猜是因为底层的 CassandraSessionFactoryBean bean 是一个单例。这导致 未配置的 columnfamily columnfamily2
这里还有一些提供上下文的日志
调试 org.springframework.beans.factory.support.DefaultListableBeanFactory - 返回单例 bean 'entityManagerFactory' 的缓存实例 调试 org.springframework.beans.factory.support.DefaultListableBeanFactory - 返回单例 bean 'session' 的缓存实例 调试 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】:嗯。无法评论马修亚当斯的答案。但这将重用会话对象,因为 AbstractCassandraConfiguration 在所有相关的 getter 上都用 @Bean 注释。
在一个类似的设置中,我最初让它覆盖所有的 getter,并专门给它们不同的 bean 名称。但是由于 Spring 仍然声称需要带有名称的 bean。我现在必须制作一个 AbstractCassandraConfiguration 的副本,没有可以继承的注释。
确保公开 CassandraTemplate,以便在使用 @EnableCassandraRepositories 时可以引用它。
我还有一个 AbstractClusterConfiguration 的单独实现,用于公开一个通用 CassandraCqlClusterFactoryBean,以便重用底层连接。
编辑: 我想根据 bclarance 链接的电子邮件线程,应该真正尝试重用 Session 对象。似乎 Spring Data Cassandra 并没有真正为此设置
【讨论】:
我的方法的一个问题是 Session 对象是在 CassandraCqlSessionFactoryBean 的 afterPropertiesSet 中创建的。所以它需要是 Spring 中的 Bean 才能发生【参考方案5】:工作应用示例: http://valchkou.com/spring-boot-cassandra.html#multikeyspace
你需要覆盖默认bean的idea: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>
// ....
【讨论】:
找不到存储库【参考方案6】:在我的例子中,我有一个 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);
【讨论】:
以上是关于spring-data-cassandra 存储库的多个键空间支持?的主要内容,如果未能解决你的问题,请参考以下文章
使用Spring-data-cassandra查询具有复合主键的表