Создайте пространство ключей, таблицу и динамически создавайте таблицы с помощью Spring Data Cassandra

используя Cassandra, я хочу динамически создавать пространство ключей и таблицы с помощью приложения Spring Boot. Я использую конфигурацию на основе Java.

У меня есть сущность, аннотированная @Table, схему которой я хочу создать до запуска приложения, поскольку она имеет фиксированные поля, которые известны заранее.

однако в зависимости от зарегистрированного пользователя я также хочу создать дополнительные таблицы для этих пользователей динамически и иметь возможность вставлять записи в эти таблицы.

может кто-нибудь направить меня к некоторым ресурсам, которые я могу использовать или указать мне в правильном направлении, как решить эти проблемы. Большое спасибо за помощь!

5 ответов


проще всего было бы добавить Данные Стартера Spring Boot Cassandra зависимость в Весна Загрузки приложение, например...

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

кроме того, это добавит Весна Данных Cassandra зависимость к вашему заявлению.

С Весна Данных Cassandra, вы можете настроить Keyspace(Ы) вашего приложения с помощью CassandraClusterFactoryBean (точнее, производный класс... CassandraCqlClusterFactoryBean) путем вызова setKeyspaceCreations (: Set) метод.

на KeyspaceActionSpecification класс довольно понятен. Вы даже можете создать один с KeyspaceActionSpecificationFactorybean добавьте Set а затем передайте это setKeyspaceCreations(..) метод CassandraClusterFactoryBean.

для создания таблиц приложения вам по существу просто нужно аннотировать объект(ы) домена приложения) (сущности) использование SD Cassandra @Table аннотация и убедитесь, что ваши объекты/сущности домена можно найти на пути к классам приложения.

в частности, вы можете иметь ваши приложения @Configuration класс расширения SD Cassandra AbstractClusterConfiguration класса. Там вы найдете getEntityBasePackages():строка[] метод, который можно переопределить для предоставления расположения пакетов, содержащих домен приложения классы объектов / сущностей, которые SD Cassandra затем будет использовать для сканирование на @Table домен объект/объекты.

С приложением @Table объект/объекты домена правильно идентифицированы, вы устанавливаете SD Cassandra SchemaAction to CREATE С помощью CassandraSessionFactoryBean метод setSchemaAction (: SchemaAction). Это создаст таблицы в вашем пространстве ключей для всех объектов/сущностей домена, найденных во время сканирования, предоставив вам выявлен правильное пространство ключей на вашем CassandraSessionFactoryBean надлежащим образом.

очевидно, что если ваше приложение создает / использует несколько Keyspaces, вам нужно будет создать отдельный CassandraSessionFactoryBean для каждого ключа, с entityBasePackages свойства конфигурации соответствующее значение для лиц, принадлежащих к определенной скорости, так что связанные таблицы создаются в скорости.

сейчас...

для "дополнительных" таблиц на одного пользователя это довольно сложно и хитрый.

вы можете использовать профили Spring здесь, однако профили обычно применяются только при запуске. Если другой пользователь входит в уже запущенное приложение, вам нужен способ предоставить дополнительные @Configuration занятия к весне ApplicationContext во время выполнения.

код Весна Загрузки приложение может ввести ссылку на AnnotationConfigApplicationContext, а затем использовать его в событии входа в систему программно зарегистрироваться дополнительные @Configuration классы, основанные на пользователе, который вошел в приложение. Вы должны следовать за своим register(Class...) вызов(ы) с ApplicationContext.refresh().

вам также необходимо соответствующим образом обрабатывать ситуацию, когда таблицы уже существуют.

в настоящее время это не поддерживается в SD Cassandra, но см. DATACASS-219 для получения дополнительной информации.

технически было бы намного проще создать все возможные таблицы, необходимые приложению для всех пользователей во время выполнения и используйте параметры безопасности Cassandra для ограничения доступа отдельных пользователей по ролям и назначенным разрешениям.

другой вариант может быть просто создать временные Keyspaces и / или таблицы по мере необходимости, когда пользователь входит в приложение, отбросьте их, когда пользователь выходит из системы.

ясно, что здесь есть много разных вариантов, и это сводится больше к архитектурным решениям, компромиссам и соображениям, а затем делает техническую осуществимость, поэтому осторожный.

надеюсь, что это помогает.

Ура!


следующий класс конфигурации 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;
    }

}

следующее Кассандра конфигурации создаст пространство ключей, когда оно не существует, а также запустит сценарий запуска, указанный

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

}

этот ответ вдохновлен ответом Вишваната.

мой 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 на cassandra.yml файл затем используйте @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)));
}

для определения ваших varaibles используйте pplication.properties или :

cassandra:
  keyspace: yout_keyspace_name

используя файлы конфигурации вместо жестко закодированных строк, вы можете опубликовать свой код, например, на GitHub, не публикуя свои пароли и entrypoints (.gitignore файлы), которые могут представлять угрозу безопасности.