spring-data-cassandra存储库支持多个密钥空间?

时间:2014-09-10 16:01:59

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

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。但它没有解释是否可以使用存储库来完成?

6 个答案:

答案 0 :(得分:5)

工作APP示例: http://valchkou.com/spring-boot-cassandra.html#multikeyspace

您需要的构思会覆盖默认bean:s​​essionfactory和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);
    }
}