web-dev-qa-db-fra.com

Créer des espaces clés, des tables et générer des tables de manière dynamique à l'aide de Spring Data Cassandra

À l'aide de Cassandra, je souhaite créer dynamiquement un espace de clés et des tables à l'aide de l'application Spring Boot. J'utilise une configuration basée sur Java. 

J'ai une entité annotée avec @Table dont je souhaite créer le schéma avant le démarrage de l'application car elle possède des champs fixes connus auparavant. 

Cependant, en fonction de l'utilisateur connecté, je souhaite également créer des tables supplémentaires pour ces utilisateurs de manière dynamique et pouvoir y insérer des entrées. 

Quelqu'un peut-il me guider vers des ressources que je peux utiliser ou me diriger dans la bonne direction pour résoudre ces problèmes. Merci beaucoup pour l'aide!

8
Anu

La solution la plus simple consiste à ajouter la Spring Boot Starter Data Cassandra dependency à votre Spring Boot application, comme ...

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-cassandra</artifactId>
  <version>1.3.5.RELEASE</version>
</dependency>

De plus, ceci ajoutera le Spring Data Cassandradépendance à votre application.

Avec Spring Data Cassandra, vous pouvez configurer le ou les espaces de clé de votre application à l'aide de la variable CassandraClusterFactoryBeanou plus précisément de la sous-classe ... CassandraCqlClusterFactoryBean) en appelant la méthode _ (setKeyspaceCreations (: Set) .

KeyspaceActionSpecification class est assez explicite. Vous pouvez même en créer un avec la KeyspaceActionSpecificationFactoryBean , ajoutez-le à une Set puis transmettez-le à la méthode setKeyspaceCreations(..) sur CassandraClusterFactoryBean.

Pour générer les tables de l'application, il vous suffit essentiellement d'annoter votre ou vos objets de domaine d'application (entités) à l'aide de la SD Cassandra @Table annotation) et de vous assurer que vos objets de domaine/entités se trouvent sur le CLASSPATH de l'application.

Spécifiquement, vous pouvez avoir votre classe d'application @Configuration étendre le SD Cassandra AbstractClusterConfiguration class. Vous y trouverez la méthode getEntityBasePackages (): String [] que vous pouvez remplacer pour fournir les emplacements de package contenant votre application). classes d’objet/entité de domaine, que SD Cassandra utilisera ensuite pour analyser scan for @Table).

Avec votre application @Table domaine objet/entités correctement identifiés, vous définissez le SD Cassandra SchemaAction sur CREATE à l’aide de la méthode CassandraSessionFactoryBean, setSchemaAction (: SchemaAction) . Cela créera des tables dans votre espace-clé pour tout objet de domaine/entités trouvées lors de l'analyse, en vous fournissant identifié l'espace de clé approprié sur votre CassandraSessionFactoryBean de manière appropriée).

Évidemment, si votre application crée/utilise plusieurs espaces de clés, vous devrez créer une variable CassandraSessionFactoryBean distincte pour chaque espace de clés, avec la propriété de configuration entityBasePackages définie de manière appropriée pour les entités appartenant à un espace de clés particulier, afin que les tables associées soient créées dans cet espace de clés. .

À présent...

Pour les tableaux "supplémentaires" par utilisateur, c'est un peu plus compliqué et délicat.

Vous pourrez peut-être utiliser les profils de ressort ici. Toutefois, les profils ne sont généralement appliqués qu'au démarrage. Si un autre utilisateur se connecte à une application en cours d'exécution, vous devez trouver un moyen de fournir des classes @Configuration supplémentaires à la variable Spring ApplicationContext au moment de l'exécution.

Votre Spring Boot application peut injecter une référence à une AnnotationConfigApplicationContext, puis l’utiliser sur un événement de connexion pour programmer register additional @Configuration) en fonction de l’utilisateur qui s’est connecté à l’application. Vous devez suivre votre register(Class...) appel (s) avec ApplicationContext.refresh().

Vous devez également gérer correctement la situation dans laquelle les tables existent déjà.

Cela n’est actuellement pas pris en charge par SD Cassandra, mais reportez-vous à la section DATACASS-219 pour plus de détails).

Techniquement, il serait beaucoup plus simple de créer toutes les tables possibles nécessaires à l'application pour tous les utilisateurs au moment de l'exécution et d'utiliser les paramètres de sécurité de Cassandra pour limiter l'accès des utilisateurs individuels par rôle et autorisations attribuées.

Une autre option consiste peut-être simplement à créer des espaces-clés temporaires et/ou des tables temporaires, selon les besoins, lorsqu'un utilisateur se connecte à l'application, à les supprimer dès qu'il se déconnecte.

De toute évidence, il y a beaucoup de choix différents ici, et cela se résume davantage à des décisions architecturales, à des compromis et à des considérations qu'à la faisabilité technique, alors soyez prudent.

J'espère que cela t'aides.

À votre santé!

14
John Blum

Après la configuration de printemps, la classe crée un espace de clés et des tables s’ils n’existent pas.

@Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {
    private static final String KEYSPACE = "my_keyspace";
    private static final String USERNAME = "cassandra";
    private static final String PASSWORD = "cassandra";
    private static final String NODES = "127.0.0.1"; // comma seperated nodes


    @Bean
    @Override
    public CassandraCqlClusterFactoryBean cluster() {
        CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean();
        bean.setKeyspaceCreations(getKeyspaceCreations());
        bean.setContactPoints(NODES);
        bean.setUsername(USERNAME);
        bean.setPassword(PASSWORD);
        return bean;
    }

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

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

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


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

    // Below method creates "my_keyspace" if it doesnt exist.
    private CreateKeyspaceSpecification getKeySpaceSpecification() {
        CreateKeyspaceSpecification pandaCoopKeyspace = new CreateKeyspaceSpecification();
        DataCenterReplication dcr = new DataCenterReplication("dc1", 3L);
        pandaCoopKeyspace.name(KEYSPACE);
        pandaCoopKeyspace.ifNotExists(true).createKeyspace().withNetworkReplication(dcr);
        return pandaCoopKeyspace;
    }

}
8
Enes Altınkaya

En utilisant @Enes Altınkaya, répondez: 

@Value("${cassandra.keyspace}")
private String keySpace;

@Override
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
    return Arrays.asList(
            CreateKeyspaceSpecification.createKeyspace()
                    .name(keySpace)
                    .ifNotExists()
                    .withNetworkReplication(new DataCenterReplication("dc1", 3L)));
}

Pour définir vos variables, utilisez un fichier pplication.properties ou application.yml:

cassandra:
  keyspace: yout_keyspace_name

En utilisant des fichiers de configuration au lieu de chaînes codées en dur, vous pouvez publier votre code par exemple sur GitHub sans publier vos mots de passe et points d’entrée (fichiers .gitignore), ce qui peut présenter un risque pour la sécurité.

1
NotMyFaultSir

La configuration cassandra suivante créera un espace de clé lorsqu'elle n'existe pas et exécutera également le script de démarrage spécifié

@Configuration
@PropertySource(value = {"classpath:cassandra.properties"})
@EnableCassandraRepositories
public class CassandraConfig extends AbstractCassandraConfiguration {

  @Value("${cassandra.keyspace}")
  private String cassandraKeyspace;

  @Override
  protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
    return Collections.singletonList(CreateKeyspaceSpecification.createKeyspace(cassandraKeyspace)
                .ifNotExists()
                .with(KeyspaceOption.DURABLE_WRITES, true)
                .withSimpleReplication());
  }

  @Override
  protected List<String> getStartupScripts() {
    return Collections.singletonList("CREATE TABLE IF NOT EXISTS "+cassandraKeyspace+".test(id UUID PRIMARY KEY, greeting text, occurrence timestamp) WITH default_time_to_live = 600;");
  }

}
0
Viswanath

Cette réponse est inspirée par la réponse de Viswanath.

Mon cassandra.yml se présente comme suit:


spring:
  data:
    cassandra:
      cluster-name: Test Cluster
      keyspace-name: keyspace
      port: 9042
      contact-points:
        - 127.0.0.1

@Configuration
@PropertySource(value = { "classpath:cassandra.yml" })
@ConfigurationProperties("spring.data.cassandra")
@EnableCassandraRepositories(basePackages = "info.vishrantgupta.repository")
public class CassandraConfig extends AbstractCassandraConfiguration {

    @Value("${keyspacename}")
    protected String keyspaceName;

    @Override
    protected String getKeyspaceName() {
        return this.keyspaceName;
    }

    @Override
    protected List getKeyspaceCreations() {
        return Collections.singletonList(CreateKeyspaceSpecification
                .createKeyspace(keyspaceName).ifNotExists()
                .with(KeyspaceOption.DURABLE_WRITES, true)
                .withSimpleReplication());
    }

    @Override
    protected List getStartupScripts() {
        return Collections.singletonList("CREATE KEYSPACE IF NOT EXISTS "
                + keyspaceName + " WITH replication = {"
                + " 'class': 'SimpleStrategy', "
                + " 'replication_factor': '3' " + "};");

    }
}

Vous devrez peut-être personnaliser @ConfigurationProperties("spring.data.cassandra"), si votre configuration commence par cassandra dans le fichier cassandra.yml, utilisez ensuite @ConfigurationProperties("cassandra").

0
Vishrant