簡體   English   中英

spring-data-cassandra 存儲庫的多鍵空間支持?

[英]Multiple keyspace support for spring-data-cassandra repositories?

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 是否支持多個鍵空間存儲庫? 我找到多個鍵空間引用的唯一地方是這里 但它沒有解釋這是否可以通過存儲庫完成?

工作應用程序示例: http : //valchkou.com/spring-boot-cassandra.html#multikeyspace

您需要覆蓋默認 bean 的想法:sessionfactory 和模板

樣本:

1) 應用程序.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> {
// ....
}

嘗試為每個鍵空間顯式命名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 時遇到了異常。對列族 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:未配置的列族分片組; 嵌套的異常是 com.datastax.driver.core.exceptions.InvalidQueryException: unconfigured columnfamily columnfamily2 at org.springframework.cassandra.support.CassandraExceptionTranslator.translateExceptionIfPossible(CassandraExceptionTranslator.java:116) at org.springframework.cassandra.config.CassandraCql SessionFactoryBeansIf( CassandraCqlSessionFactoryBean.java:74)

唔。 無法評論 matthew-adams 的答案。 但這將重用會話對象,因為 AbstractCassandraConfiguration 在所有相關的 getter 上都用 @Bean 注釋。

在類似的設置中,我最初讓它覆蓋所有的 getter 並專門為它們提供不同的 bean 名稱。 但是由於 Spring 仍然聲稱需要帶有名稱的 bean。 我現在不得不制作一個 AbstractCassandraConfiguration 的副本,沒有可以繼承的注釋。

確保公開 CassandraTemplate,以便在使用時可以從 @EnableCassandraRepositories 中引用它。

我還有一個單獨的 AbstractClusterConfiguration 實現來公開一個通用的 CassandraCqlClusterFactoryBean,以便重用底層連接。

編輯:我猜根據 bclarance 鏈接的電子郵件線程,應該真正嘗試重用 Session 對象。 似乎 Spring Data Cassandra 並沒有真正為此設置的方式

就我而言,我有一個 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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM