使用Cassandra,我想使用Spring Boot应用程序动态创建键空间和表。我正在使用基于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
方法使用CassandraCqlClusterFactoryBean
(或更确切地说,子类... setKeyspaceCreations(:Set))配置应用程序的Keyspace。
KeyspaceActionSpecification类非常不言自明。您甚至可以使用KeyspaceActionSpecificationFactoryBean创建一个,将其添加到Set
,然后将其传递给setKeyspaceCreations(..)
上的CassandraClusterFactoryBean
方法。
为了生成应用程序的表,您基本上只需要使用SD Cassandra @Table批注来注释您的应用程序域对象(实体),并确保可以在应用程序的CLASSPATH上找到您的域对象/实体。
具体来说,您可以让您的应用程序@Configuration
类扩展SD Cassandra AbstractClusterConfiguration类。在那里,您将找到可以覆盖的getEntityBasePackages():String[]方法,以提供包含应用程序域对象/实体类的包位置,然后SD Cassandra将使用scan来获取@Table
域对象/实体。
在您的应用程序@Table
域对象/实体正确识别后,使用SchemaAction方法CREATE
将SD Cassandra CassandraSessionFactoryBean
设置为setSchemaAction(:SchemaAction)。这将在您的Keyspace中为扫描期间找到的所有域对象/实体创建表格,为您在identified上适当地为CassandraSessionFactoryBean
提供正确的Keyspace。
显然,如果您的应用程序创建/使用多个Keyspace,您将需要为每个Keyspace创建一个单独的CassandraSessionFactoryBean
,并为适合特定Keyspace的实体设置适当的entityBasePackages
配置属性,以便在该Keyspace中创建关联的表。
现在...
对于每个用户的“附加”表,这是相当复杂和棘手的。
您可以在此处利用Spring Profiles,但是,配置文件通常仅在启动时应用。如果其他用户登录到已在运行的应用程序,则需要一种方法在运行时向Spring @Configuration
提供其他ApplicationContext
类。
您的Spring Boot应用程序可以注入对AnnotationConfigApplicationContext
的引用,然后在登录事件上使用它以编程方式register基于登录应用程序的用户的其他@Configuration
类。你需要跟随你的register(Class...)
电话与ApplicationContext.refresh()
。
您还需要适当地处理表已存在的情况。
SD Cassandra目前不支持此功能,但请参阅DATACASS-219了解更多详情。
从技术上讲,在运行时为所有用户创建应用程序所需的所有可能的表并使用Cassandra的安全设置来限制按角色和分配的权限的单个用户访问将简单得多。
另一种选择可能是在用户登录应用程序时根据需要创建临时Keyspace和/或表,在用户注销时删除它们。
显然,这里有很多不同的选择,它更多地归结为架构决策,权衡和考虑,然后它具有技术可行性,所以要小心。
希望这可以帮助。
干杯!
在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;
}
}
使用@Enes Altinkaya回答:
@Value("${cassandra.keyspace}")
private String keySpace;
@Override
protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
return Arrays.asList(
CreateKeyspaceSpecification.createKeyspace()
.name(keySpace)
.ifNotExists()
.withNetworkReplication(new DataCenterReplication("dc1", 3L)));
}
要定义变量,请使用qazxsw poi或qazxsw poi文件:
application.properties
使用配置文件而不是硬编码字符串,您可以在例如GitHub上发布代码,而无需发布可能存在安全风险的密码和入口点(application.yml
文件)。
以下cassandra配置将在不存在时创建密钥空间,并运行指定的启动脚本
cassandra:
keyspace: yout_keyspace_name
这个答案的灵感来自Viswanath的回答。
我的.gitignore
看起来如下:
@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
对于表的创建,您可以在application.properties文件中使用它
cassandra.yml