创建键空间,table 并使用 Spring Data Cassandra 动态生成 tables

Create keyspace, table and generate tables dynamically using Spring Data Cassandra

使用 Cassandra,我想使用 Spring 引导应用程序动态创建键空间和表。我正在使用基于 Java 的配置。

我有一个用@Table 注释的实体,我想在应用程序启动之前创建它的模式,因为它有预先知道的固定字段。

然而,根据登录用户的不同,我还想为这些用户动态创建额外的表,并能够向这些表中插入条目。

有人可以指导我找到一些我可以利用的资源,或者为我指明正确的方向以解决这些问题。非常感谢您的帮助!

最简单的做法是将 Spring Boot Starter Data Cassandra 依赖项添加到您的 Spring Boot 应用程序,就像这样...

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

此外,这会将 Spring Data Cassandra dependency 添加到您的应用程序。

使用 Spring Data Cassandra,您可以使用 CassandraClusterFactoryBean(或更准确地说,subclass... CassandraCqlClusterFactoryBean) 通过调用 setKeyspaceCreations(:Set) 方法。

KeyspaceActionSpecification class is pretty self-explanatory. You can even create one with the KeyspaceActionSpecificationFactoryBean,将其添加到 Set,然后将其传递给 CassandraClusterFactoryBean.

上的 setKeyspaceCreations(..) 方法

为了生成应用程序的表,您基本上只需要使用 SD Cassandra @Table 注释来注释您的应用程序域对象(实体),并确保您的域 objects/entities 可以在应用程序的 CLASSPATH 中找到。

具体来说,您可以让您的应用程序 @Configuration class 为 @Table 域 object/entities.

扩展 SD Cassandra AbstractClusterConfiguration class. There, you will find the getEntityBasePackages():String[] method that you can override to provide the package locations containing your application domain object/entity classes, which SD Cassandra will then use to scan

在您的应用程序 @Table 域 object/entities 正确识别后,您可以在 CassandraSessionFactoryBean 上适当地设置 SD Cassandra SchemaAction to CREATE using the CassandraSessionFactoryBean method, setSchemaAction(:SchemaAction). This will create Tables in your Keyspace for all domain object/entities found during the scan, providing you identified 正确的键空间。

显然,如果您的应用程序 creates/uses 多个键空间,您将需要为每个键空间创建一个单独的 CassandraSessionFactoryBean,并适当地设置 entityBasePackages 配置 属性属于特定键空间的实体,以便在该键空间中创建关联的表。

现在...

对于每个用户的 "additional" 个表,这要复杂和棘手得多。

您可以在此处利用 Spring 配置文件,但是,配置文件通常仅在启动时应用。如果不同的用户登录到已经 运行 的应用程序,您需要一种方法在运行时向 Spring ApplicationContext 提供额外的 @Configuration classes。

您的 Spring Boot 应用程序可以注入对 AnnotationConfigApplicationContext 的引用,然后在登录事件中以编程方式使用它 register附加 @Configuration classes 基于登录应用程序的用户。您需要通过 ApplicationContext.refresh().

跟进您的 register(Class...) 电话

您还需要适当处理Tables已经存在的情况。

SD Cassandra 目前不支持此功能,但请参阅 DATACASS-219 了解更多详细信息。

从技术上讲,在运行时为所有用户创建应用程序所需的所有可能表并使用 Cassandra 的安全设置按角色和分配的权限限制单个用户访问会简单得多。

另一种选择可能只是在用户登录应用程序时根据需要创建临时键空间and/or表,在用户注销时删除它们。

显然,这里有很多不同的选择,它更多地归结为架构决策、权衡和考虑,然后是技术可行性,所以要小心。

希望这对您有所帮助。

干杯!

按照 spring 配置 class 创建键空间和表(如果它们不存在)。

@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;
    }

}

下面的cassandra配置会在keyspace不存在的时候创建,也会运行启动脚本指定

@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;");
  }

}

这个答案的灵感来自于 Viswanath 的答案。

我的 cassandra.yml 看起来如下:


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' " + "};");

    }
}

您可能需要自定义 @ConfigurationProperties("spring.data.cassandra"),如果您的配置在 cassandra.yml 文件中以 cassandra 开头,则使用 @ConfigurationProperties("cassandra")

使用@Enes Altınkaya 回答:

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

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

要定义变量,请使用 application.propertiesapplication.yml 文件:

cassandra:
  keyspace: yout_keyspace_name

使用配置文件而不是硬编码字符串,您可以在 GitHub 上发布您的代码,而无需发布您的密码和入口点(.gitignore 文件),这可能存在安全风险。

对于 table 的创作,您可以在 application.properties 文件中使用它

spring.data.cassandra.schema-action=CREATE_IF_NOT_EXISTS