【问题标题】:Multiple keyspace support for spring-data-cassandra repositories?spring-data-cassandra 存储库的多个键空间支持?
【发布时间】: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。但它没有解释这是否可以通过存储库完成?

【问题讨论】:

  • 我将此转发给处理大部分存储库编码的工程师,以便为您解答。请坐好。

标签: java spring spring-data spring-data-cassandra


【解决方案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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      • 2021-03-28
      • 2017-12-27
      • 1970-01-01
      相关资源
      最近更新 更多