Search code examples
springspring-bootcassandraspring-dataspring-data-cassandra

Spring Cassandra: Creating Schema in run time in another keyspace


I have Spring Boot 2 project with spring-cassandra where I am creating keyspace in runtime with @RefreshScope and I am executing query to use that keyspace but the schemas are not created from the entity with @Table annotation.

When I start the application a new keyspace is created if does not exists and the schema is created. After that I change keyspace in app.properties and sent POST request to actuator/refresh. New keyspace is created and its being used but the schema are not created in that keyspace.

This is my Cassandra Config:

@Configuration
@EnableCassandraRepositories
public class CassandraConfig extends AbstractCassandraConfiguration {

  @Value("${cassandra.port}")
  private int cassandraPort;
  @Value("${cassandra.keyspace}")
  private String KEYSPACE;
  @Value("${cassandra.contactpoints}")
  private String NODES;

  @Bean
  @Override
  public CassandraCqlClusterFactoryBean cluster() {
    CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean();
    bean.setKeyspaceCreations(getKeyspaceCreations());
    bean.setContactPoints(NODES);
    bean.setPort(cassandraPort);
    return bean;
  }

  @Override
  public SchemaAction getSchemaAction() {
    return SchemaAction.CREATE_IF_NOT_EXISTS;
  }

  @Override
  protected String getKeyspaceName() {
    return KEYSPACE;
  }

  @Override
  protected String getContactPoints() {
    return NODES;
  }

  @Override
  protected int getPort() {
    return cassandraPort;
  }

  @Override
  public String[] getEntityBasePackages() {
    return new String[] {"package.entities"};
  }

  @Override
  protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
    List<CreateKeyspaceSpecification> createKeyspaceSpecifications = new ArrayList<>();
    createKeyspaceSpecifications.add(getKeySpaceSpecification());
    return createKeyspaceSpecifications;
  }

  // Below method creates "keyspace" if it doesn't exist.
  private CreateKeyspaceSpecification getKeySpaceSpecification() {
    DataCenterReplication dcr = DataCenterReplication.of("datacenter1", 3L);
    return CreateKeyspaceSpecification.createKeyspace(KEYSPACE)
        .ifNotExists()
        .withNetworkReplication(dcr);
  }
}

And this is the RefreshScope class:

@Component
class MySessionRefresh extends AbstractCassandraConfiguration{

  @Autowired
  Environment env;

  @Autowired
  Session session;

  @EventListener
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public void handle(RefreshScopeRefreshedEvent event) {

    String keyspace = env.getProperty("cassandra.keyspace");
    session.execute("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " WITH REPLICATION = { 'class' : 'NetworkTopologyStrategy', 'datacenter1' : 3 };");
    session.execute("USE " + keyspace + " ;");

  }

What else I need to do to auto-create schemas from entity with @Table in runtime for the new keyspace?


Solution

  • Schema creation in Spring Data Cassandra is tied to the session factory (CassandraSessionFactoryBean), keyspace creation is tied to the Cluster instance (CassandraClusterFactoryBean). You need to put @RefreshScope on both factories.

    Keep in mind that refreshing will disrupt your Cassandra operations. You also should note that schema creation is not intended for production use. It's designed with integration tests and rapid application development in mind.