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查询具有复合主键的表

卡桑德拉+弹簧数据

Spring Data Cassandra 计数器更新

Artifactory 无法更新存储库 - 存储库聚合另一个具有不匹配包类型的存储库

Nexus 原始存储库与 Maven 存储库

Git存储库中的Git存储库[重复]