spring-data-cassandra仓库支持多个键空间吗?

10

Spring Data Cassandra是否支持在同一个应用程序上下文中使用多个keyspace仓库?我正在使用以下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支持多个键空间存储库吗?我发现引用多个键空间的唯一地方是这里。但它没有解释是否可以使用存储库完成此操作。


我会将此转发给处理大部分代码库编码的工程师,以便为您获取答案。请耐心等待。 - David Webb
6个回答

5

工作应用程序示例:

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) 将每个keyspace的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> {
// ....
}

找不到存储库 - Anuj

2

尝试为每个keyspace明确命名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());
}

我认为那可能是解决之道。如果行不通,请回复留言。


我会尝试这个并回来。 - Saket
找不到存储库bean。 - Anuj

0

我尝试了这种方法。但是在尝试访问列族2时遇到了异常。对列族1的操作似乎没问题。

我猜测这是因为底层的CassandraSessionFactoryBean bean是单例的。这导致了未配置的列族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: 未配置的列族shardgroup;嵌套异常是com.datastax.driver.core.exceptions.InvalidQueryException: 未配置的列族columnfamily2 at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:116) at org.springframework.cassandra.config.CassandraCqlSessionFactoryBean.translateExceptionIfPossible(CassandraCqlSessionFactoryBean.java:74)


0

看起来建议在一个会话中管理的查询中使用完全限定的键空间名称,因为该会话并不是非常轻量级的。
请参见此处的参考资料。


1
不错的发现。值得注意的是,你链接的例子有100个keyspace,而这个只有2个。两个不太轻量级的会话可能是可以接受的,而100个会导致问题。 - M. Justin

0

嗯。无法评论matthew-adams的答案。但是,由于AbstractCassandraConfiguration在所有相关getter上都带有@Bean注释,因此将重用会话对象。

在类似的设置中,我最初通过覆盖所有getter并明确给它们不同的bean名称来使其工作。但由于Spring仍然声称需要具有这些名称的bean。现在,我不得不制作一个没有注释的AbstractCassandraConfiguration副本,以便我可以继承它。

确保公开CassandraTemplate,以便您可以在使用@ EnableCassandraRepositories时引用它。

我还有一个单独的AbstractClusterConfiguration实现,以公开常见的CassandraCqlClusterFactoryBean,以便底层连接被重用。

编辑: 根据bclarance链接的电子邮件线程,我想应该真正尝试重用Session对象。不过,似乎Spring Data Cassandra并没有为此进行设置


我的方法存在一个问题,即Session对象是在CassandraCqlSessionFactoryBean的afterPropertiesSet中创建的。因此,它需要成为Spring中的一个Bean才能发生这种情况。 - Kristoffer

0
在我的情况下,我有一个Spring Boot应用程序,其中大部分存储库位于一个keyspace中,只有两个存储库位于第二个keyspace中。 我保留了第一个keyspace的默认Spring Boot配置,并使用与Spring Boot自动配置相同的配置方法手动配置了第二个keyspace。
@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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接