简体   繁体   English

使用Spring Data Cassandra动态创建键空间,表和生成表

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

Using Cassandra, I want to create keyspace and tables dynamically using Spring Boot application. 使用Cassandra,我想使用Spring Boot应用程序动态创建键空间和表。 I am using Java based configuration. 我正在使用基于Java的配置。

I have an entity annotated with @Table whose schema I want to be created before application starts up since it has fixed fields that are known beforehand. 我有一个用@Table注释的实体,我希望在应用程序启动之前创建它的模式,因为它具有事先已知的固定字段。

However depending on the logged in user, I also want to create additional tables for those user dynamically and be able to insert entries to those tables. 但是,根据登录用户的不同,我还想动态地为这些用户创建附加表,并能够向这些表插入条目。

Can somebody guide me to some resources that I can make use of or point me in right direction in how to go about solving these issues. 有人可以引导我使用一些我可以利用的资源,或指出我如何解决这些问题。 Thanks a lot for help! 非常感谢您的帮助!

The easiest thing to do would be to add the Spring Boot Starter Data Cassandra dependency to your Spring Boot application, like so... 最简单的方法是将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>

In addition, this will add the Spring Data Cassandra dependency to your application. 此外,这将为您的应用程序添加Spring Data Cassandra 依赖项

With Spring Data Cassandra , you can configure your application's Keyspace(s) using the CassandraClusterFactoryBean (or more precisely, the subclass... CassandraCqlClusterFactoryBean ) by calling the setKeyspaceCreations(:Set) method. 使用Spring Data Cassandra ,您可以通过调用setKeyspaceCreations(:Set)方法,使用CassandraClusterFactoryBean (或更准确地说,子类... CassandraCqlClusterFactoryBean )配置应用程序的Keyspace。

The KeyspaceActionSpecification class is pretty self-explanatory. KeyspaceActionSpecification类非常明显。 You can even create one with the KeyspaceActionSpecificationFactoryBean , add it to a Set and then pass that to the setKeyspaceCreations(..) method on the CassandraClusterFactoryBean . 您甚至可以使用KeyspaceActionSpecificationFactoryBean创建一个,将其添加到Set ,然后将其传递给CassandraClusterFactoryBean上的setKeyspaceCreations(..)方法。

For generating the application's Tables, you essentially just need to annotate your application domain object(s) (entities) using the SD Cassandra @Table annotation, and make sure your domain objects/entities can be found on the application's CLASSPATH. 为了生成应用程序的表,您基本上只需要使用SD Cassandra @Table注释来注释您的应用程序域对象(实体),并确保可以在应用程序的CLASSPATH上找到您的域对象/实体。

Specifically, you can have your application @Configuration class extend the SD Cassandra AbstractClusterConfiguration class. 具体来说,您可以让应用程序@Configuration类扩展SD Cassandra AbstractClusterConfiguration类。 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 for @Table domain object/entities. 在那里,您将找到getEntityBasePackages():String []方法,您可以覆盖该方法以提供包含应用程序域对象/实体类的包位置,然后SD Cassandra将使用该方法扫描 @Table域对象/实体。

With your application @Table domain object/entities properly identified, you set the SD Cassandra SchemaAction to CREATE using the CassandraSessionFactoryBean method, setSchemaAction(:SchemaAction) . 在正确识别应用程序@Table域对象/实体的情况下,使用CassandraSessionFactoryBean方法setSchemaAction(:SchemaAction)将SD Cassandra SchemaAction设置为CREATE This will create Tables in your Keyspace for all domain object/entities found during the scan, providing you identified the proper Keyspace on your CassandraSessionFactoryBean appropriately. 这将在您的Keyspace中为扫描期间找到的所有域对象/实体创建表,这样您就可以在CassandraSessionFactoryBean上正确识别出正确的Keyspace。

Obviously, if your application creates/uses multiple Keyspaces, you will need to create a separate CassandraSessionFactoryBean for each Keyspace, with the entityBasePackages configuration property set appropriately for the entities that belong to a particular Keyspace, so that the associated Tables are created in that Keyspace. 显然,如果您的应用程序创建/使用多个Keyspace,您将需要为每个Keyspace创建一个单独的CassandraSessionFactoryBean ,并为属于特定Keyspace的实体设置相应的entityBasePackages配置属性,以便在该Keyspace中创建关联的表。

Now... 现在...

For the "additional" Tables per user, that is quite a bit more complicated and tricky. 对于每个用户的“附加”表,这是相当复杂和棘手的。

You might be able to leverage Spring Profiles here, however, profiles are generally only applied on startup. 您可以在此处利用Spring Profiles,但是,配置文件通常仅在启动时应用。 If a different user logs into an already running application, you need a way to supply additional @Configuration classes to the Spring ApplicationContext at runtime. 如果其他用户登录到已在运行的应用程序,则需要一种在运行时向Spring ApplicationContext提供其他@Configuration类的方法。

Your Spring Boot application could inject a reference to a AnnotationConfigApplicationContext , and then use it on a login event to programmatically register additional @Configuration classes based on the user who logged into the application. Spring Boot应用程序可以注入对AnnotationConfigApplicationContext的引用,然后在登录事件上使用它,以编程方式根据登录应用程序的用户注册其他@Configuration类。 You need to follow your register(Class...) call(s) with an ApplicationContext.refresh() . 您需要使用ApplicationContext.refresh()跟随您的register(Class...)调用。

You also need to appropriately handle the situation where the Tables already exist. 您还需要适当地处理表已存在的情况。

This is not currently supported in SD Cassandra, but see DATACASS-219 for further details. SD Cassandra目前不支持此功能,但有关详细信息,请参阅DATACASS-219

Technically, it would be far simpler to create all the possible Tables needed by the application for all users at runtime and use Cassandra's security settings to restrict individual user access by role and assigned permissions. 从技术上讲,在运行时为所有用户创建应用程序所需的所有可能的表并使用Cassandra的安全设置来限制按角色和分配的权限的单个用户访问将简单得多。

Another option might be just to create temporary Keyspaces and/or Tables as needed when a user logs in into the application, drop them when the user logs out. 另一种选择可能是在用户登录应用程序时根据需要创建临时Keyspace和/或表,在用户注销时删除它们。

Clearly, there are a lot of different choices here, and it boils down more to architectural decisions, tradeoffs and considerations then it does technical feasibility, so be careful. 显然,这里有很多不同的选择,它更多地归结为架构决策,权衡和考虑,然后它具有技术可行性,所以要小心。

Hope this helps. 希望这可以帮助。

Cheers! 干杯!

Following spring configuration class creates keyspace and tables if they dont exist. 在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;
    }

}

Using @Enes Altınkaya answer: 使用@EnesAltı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)));
}

To define your varaibles use an application.properties or application.yml file: 要定义变量,请使用application.propertiesapplication.yml文件:

cassandra:
  keyspace: yout_keyspace_name

Using config files instead of hardcoded strings you can publish your code on for example GitHub without publishing your passwords and entrypoints ( .gitignore files) which may be a security risk. 使用配置文件而不是硬编码字符串,您可以在例如GitHub上发布代码,而无需发布可能存在安全风险的密码和入口点( .gitignore文件)。

The following cassandra configuration will create a keyspace when it does not exist and also run the start-up script specified 以下cassandra配置将在不存在时创建密钥空间,并运行指定的启动脚本

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

}

This answer is inspired by Viswanath's answer. 这个答案的灵感来自Viswanath的回答。

My cassandra.yml looks as follows: 我的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' " + "};");

    }
}

You might have to customize @ConfigurationProperties("spring.data.cassandra") , if your configuration starts with cassandra in cassandra.yml file then use @ConfigurationProperties("cassandra") 您可能需要定制@ConfigurationProperties("spring.data.cassandra")如果你的配置与启动cassandracassandra.yml文件,然后使用@ConfigurationProperties("cassandra")

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

spring.data.cassandra.schema-action=CREATE_IF_NOT_EXISTS

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM