【问题标题】:Create keyspace, table and generate tables dynamically using Spring Data Cassandra使用 Spring Data Cassandra 动态创建键空间、表和生成表
【发布时间】:2016-09-18 01:45:22
【问题描述】:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    最简单的做法是将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,您可以通过调用setKeyspaceCreations(:Set) 方法使用CassandraClusterFactoryBean(或更准确地说,子类...CassandraCqlClusterFactoryBean)配置应用程序的键空间.

    KeyspaceActionSpecification 类是不言自明的。您甚至可以使用KeyspaceActionSpecificationFactoryBean 创建一个,将其添加到Set,然后将其传递给CassandraClusterFactoryBean 上的setKeyspaceCreations(..) 方法。

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

    具体来说,您可以让您的应用程序 @Configuration 类扩展 SD Cassandra AbstractClusterConfiguration 类。在那里,您将找到 getEntityBasePackages():String[] 方法,您可以覆盖该方法以提供包含应用程序域对象/实体类的包位置,然后 SD Cassandra 将使用该方法到 scan 以获取 @Table 域对象/实体。

    在正确识别您的应用程序@Table 域对象/实体后,您可以使用CassandraSessionFactoryBean 方法setSchemaAction(:SchemaAction) 将SD Cassandra SchemaAction 设置为CREATE。这将在您的 Keyspace 中为扫描期间找到的所有域对象/实体创建表,为您提供 identified 适当的 CassandraSessionFactoryBean 上的 Keyspace。

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

    现在...

    对于每个用户的“附加”表,这有点复杂和棘手。

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

    您的Spring Boot 应用程序可以注入对AnnotationConfigApplicationContext 的引用,然后在登录事件中使用它以编程方式根据登录到的用户register 附加@Configuration 类应用。您需要使用ApplicationContext.refresh() 关注您的register(Class...) 电话。

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

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

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

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

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

    希望这会有所帮助。

    干杯!

    【讨论】:

      【解决方案2】:

      下面的 spring 配置类创建键空间和表(如果它们不存在)。

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

      【讨论】:

      • 我已遵循此代码,但仍然无法在应用程序启动时创建键空间和表。还有什么我想念的吗?请指导我。
      【解决方案3】:

      使用@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 文件),这可能会带来安全风险。

      【讨论】:

        【解决方案4】:

        下面的cassandra配置会在keyspace不存在的时候创建一个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;");
          }
        
        }
        

        【讨论】:

          【解决方案5】:

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

          spring.data.cassandra.schema-action=CREATE_IF_NOT_EXISTS
          

          【讨论】:

            【解决方案6】:

            这个答案的灵感来自维斯瓦纳特的回答。

            我的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")

            【讨论】:

              猜你喜欢
              • 2019-10-29
              • 2018-07-23
              • 2014-10-11
              • 1970-01-01
              • 2020-12-13
              • 2019-06-12
              • 2016-05-10
              • 2020-10-31
              • 1970-01-01
              相关资源
              最近更新 更多