此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Cassandra 4.4.0spring-doc.cn

架构管理

Apache Cassandra 是一种数据存储,在任何数据交互之前都需要架构定义。 Spring Data for Apache Cassandra 可以支持您创建架构。spring-doc.cn

CQL 规格

CQL 规范是表示 CQL DDL 操作(例如表创建或键空间删除)的抽象。 CQL 对象类型包括以下规格:spring-doc.cn

Cassandra 的变体可以支持物化视图、用户定义的函数、角色和更多对象类型。 Spring Data for Apache Cassandra 仅提供上述类型的规范。

这些可用于通过 Fluent 接口 CREATE、ALTER 和 DROP CQL 对象。 是构建此类规范的入口点。 您可以稍后使用轻松呈现规范中的 CQL。SpecificationBuilderCqlGenerator.toCql(…)spring-doc.cn

请参阅以下示例以创建密钥空间、表创建和索引创建的规范。spring-doc.cn

示例 1.指定 Cassandra 键空间
Java
CqlSpecification createKeyspace = SpecificationBuilder.createKeyspace("my_keyspace")
		.with(KeyspaceOption.REPLICATION, KeyspaceAttributes.newSimpleReplication())
		.with(KeyspaceOption.DURABLE_WRITES, true);

// results in CREATE KEYSPACE my_keyspace WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND durable_writes = true
String cql = CqlGenerator.toCql(createKeyspace);
示例 2.指定 Cassandra 表
Java
CreateTableSpecification createTable = CreateTableSpecification.createTable("my_table")
		.partitionKeyColumn("last_name", DataTypes.TEXT)
		.partitionKeyColumn("first_name", DataTypes.TEXT)
		.column("age", DataTypes.INT);

// results in CREATE TABLE my_table (last_name text, first_name text, age int, PRIMARY KEY(last_name, first_name))
String cql = CqlGenerator.toCql(createTable);
例 3.指定 Cassandra 索引
Java
CreateIndexSpecification spec = SpecificationBuilder.createIndex()
		.tableName("mytable").keys().columnName("column");

// results in CREATE INDEX ON mytable (KEYS(column))
String cql = CqlGenerator.toCql(createTable);

您可以将规范与配置 API 一起使用来定义密钥空间创建和架构操作。spring-doc.cn

Keyspaces 和生命周期脚本

首先要做的是 Cassandra 密钥空间。 键空间是共享相同复制因子和复制策略的表的逻辑分组。 Keyspace management 位于配置中,该配置具有 和 startup 和 shutdown CQL 脚本执行。CqlSessionKeyspaceSpecificationspring-doc.cn

使用规范声明密钥空间允许创建和删除密钥空间。 它从规范中派生 CQL,因此您无需自己编写 CQL。 以下示例使用 XML 指定 Cassandra 密钥空间:spring-doc.cn

示例 4.指定 Cassandra 键空间
Java
@Configuration
public class CreateKeyspaceConfiguration extends AbstractCassandraConfiguration implements BeanClassLoaderAware {

	@Override
	protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {

		CreateKeyspaceSpecification specification = SpecificationBuilder.createKeyspace("my_keyspace")
				.with(KeyspaceOption.DURABLE_WRITES, true)
				.withNetworkReplication(DataCenterReplication.of("foo", 1), DataCenterReplication.of("bar", 2));

		return Arrays.asList(specification);
	}

	@Override
	protected List<DropKeyspaceSpecification> getKeyspaceDrops() {
		return Arrays.asList(DropKeyspaceSpecification.dropKeyspace("my_keyspace"));
	}

	// ...
}
XML 格式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
  xsi:schemaLocation="
    http://www.springframework.org/schema/data/cassandra
    https://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd
    http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

    <cassandra:session>

        <cassandra:keyspace action="CREATE_DROP" durable-writes="true" name="my_keyspace">
            <cassandra:replication class="NETWORK_TOPOLOGY_STRATEGY">
              <cassandra:data-center name="foo" replication-factor="1" />
              <cassandra:data-center name="bar" replication-factor="2" />
            </cassandra:replication>
      </cassandra:keyspace>

    </cassandra:session>
</beans>
Keyspace 创建允许快速引导,而无需外部 Keyspace 管理。 这在某些情况下可能很有用,但应谨慎使用。 在应用程序关闭时删除密钥空间将从密钥空间的表中删除密钥空间和所有数据。

初始化SessionFactory

该软件包支持初始化现有的 . 有时可能需要初始化在某个位置的服务器上运行的密钥空间。org.springframework.data.cassandra.core.cql.session.initSessionFactoryspring-doc.cn

初始化 Keyspace

您可以提供在配置的密钥空间中初始化和关闭时执行的任意 CQL,如下面的 Java 配置示例所示:CqlSessionspring-doc.cn

Java
@Configuration
public class KeyspacePopulatorConfiguration extends AbstractCassandraConfiguration {

	@Nullable
	@Override
	protected KeyspacePopulator keyspacePopulator() {
		return new ResourceKeyspacePopulator(new ClassPathResource("com/foo/cql/db-schema.cql"),
				new ClassPathResource("com/foo/cql/db-test-data.cql"));
	}

	@Nullable
	@Override
	protected KeyspacePopulator keyspaceCleaner() {
		return new ResourceKeyspacePopulator(scriptOf("DROP TABLE my_table;"));
	}

	// ...
}
XML 格式
<cassandra:initialize-keyspace session-factory-ref="cassandraSessionFactory">
    <cassandra:script location="classpath:com/foo/cql/db-schema.cql"/>
    <cassandra:script location="classpath:com/foo/cql/db-test-data.cql"/>
</cassandra:initialize-keyspace>

前面的示例针对键空间运行两个指定的脚本。 第一个脚本创建架构,第二个脚本使用测试数据集填充表。 脚本位置也可以是带有通配符的模式,其模式采用 Spring 中用于资源的常用 Ant 样式(例如,)。 如果使用模式,则脚本将按其 URL 或 filename 的词法顺序运行。classpath*:/com/foo/**/cql/*-data.cqlspring-doc.cn

keyspace initializer 的默认行为是无条件地运行提供的脚本。 这可能并不总是您想要的 — 例如,如果您针对已经包含测试数据的 keyspace 运行脚本。 通过遵循先创建表,然后插入数据的常见模式(如前所示),可以降低意外删除数据的可能性。 如果表已存在,则第一步将失败。spring-doc.cn

但是,为了更好地控制现有数据的创建和删除,XML 名称空间提供了一些其他选项。 第一个是用于打开和关闭初始化的标志。 您可以根据环境进行设置(例如,从系统属性或环境 Bean 中提取布尔值)。 以下示例从 system 属性获取值:spring-doc.cn

<cassandra:initialize-keyspace session-factory-ref="cassandraSessionFactory"
    enabled="#{systemProperties.INITIALIZE_KEYSPACE}">    (1)
    <cassandra:script location="..."/>
</cassandra:initialize-database>
1 从名为 的系统属性中获取 的值。enabledINITIALIZE_KEYSPACE

控制现有数据发生情况的第二个选项是对故障的容忍度更高。 为此,您可以控制初始化器忽略它从脚本执行的 CQL 中的某些错误的能力,如下例所示:spring-doc.cn

Java
@Configuration
public class KeyspacePopulatorFailureConfiguration extends AbstractCassandraConfiguration {

	@Nullable
	@Override
	protected KeyspacePopulator keyspacePopulator() {

		ResourceKeyspacePopulator populator = new ResourceKeyspacePopulator(
				new ClassPathResource("com/foo/cql/db-schema.cql"));

		populator.setIgnoreFailedDrops(true);

		return populator;
	}

	// ...
}
XML 格式
<cassandra:initialize-keyspace session-factory-ref="cassandraSessionFactory" ignore-failures="DROPS">
    <cassandra:script location="..."/>
</cassandra:initialize-database>

在前面的示例中,我们表示我们预期有时脚本是针对空 keyspace 运行的,因此脚本中的某些语句会失败。 因此,失败的 CQL 语句将被忽略,但其他失败将导致异常。 如果您不想使用 tu use support (或类似功能),但又想在重新创建之前无条件地删除所有测试数据,这将非常有用。 在这种情况下,第一个脚本通常是一组语句,后跟一组语句。DROPDROPDROP …​ IF EXISTSDROPCREATEspring-doc.cn

该选项可以设置为 (default)、(忽略失败的放置)或 (ignore all failures)。ignore-failuresNONEDROPSALLspring-doc.cn

如果脚本中根本不存在字符,则每个语句都应该用 或 new line 分隔。 您可以全局控制该操作,也可以逐个脚本控制,如下例所示:;;spring-doc.cn

Java
@Configuration
public class SessionFactoryInitializerConfiguration extends AbstractCassandraConfiguration {

	@Bean
	SessionFactoryInitializer sessionFactoryInitializer(SessionFactory sessionFactory) {

		SessionFactoryInitializer initializer = new SessionFactoryInitializer();
		initializer.setSessionFactory(sessionFactory);

		ResourceKeyspacePopulator populator1 = new ResourceKeyspacePopulator();
		populator1.setSeparator(";");
		populator1.setScripts(new ClassPathResource("com/myapp/cql/db-schema.cql"));

		ResourceKeyspacePopulator populator2 = new ResourceKeyspacePopulator();
		populator2.setSeparator("@@");
		populator2.setScripts(new ClassPathResource("classpath:com/myapp/cql/db-test-data-1.cql"), //
				new ClassPathResource("classpath:com/myapp/cql/db-test-data-2.cql"));

		initializer.setKeyspacePopulator(new CompositeKeyspacePopulator(populator1, populator2));

		return initializer;
	}

	// ...
}
XML 格式
<cassandra:initialize-keyspace session-factory-ref="cassandraSessionFactory" separator="@@">
    <cassandra:script location="classpath:com/myapp/cql/db-schema.cql" separator=";"/>
    <cassandra:script location="classpath:com/myapp/cql/db-test-data-1.cql"/>
    <cassandra:script location="classpath:com/myapp/cql/db-test-data-2.cql"/>
</cassandra:initialize-keyspace>

在此示例中,两个脚本使用 as 语句分隔符,并且仅使用 . 此配置指定默认分隔符为并覆盖脚本的默认值。test-data@@db-schema.cql;@@db-schemaspring-doc.cn

如果您需要的控制比从 XML 命名空间获得的控制更多,则可以直接使用 并将其定义为应用程序中的一个组件。SessionFactoryInitializerspring-doc.cn

依赖于 Keyspace 的其他组件的初始化

一大类应用程序(那些在 Spring 上下文启动之前不使用数据库的应用程序)可以使用数据库初始化器,而不会进一步复杂化。 如果您的应用程序不是其中之一,则可能需要阅读本节的其余部分。spring-doc.cn

数据库初始化器依赖于实例并运行其初始化回调中提供的脚本(类似于 XML bean 定义中的 an、组件中的方法或实现 component 中的 method)。 如果其他 bean 依赖于相同的数据源并在初始化回调中使用会话工厂,则可能存在问题,因为数据尚未初始化。 一个常见的示例是缓存,它在应用程序启动时预先初始化并从数据库加载数据。SessionFactoryinit-method@PostConstructafterPropertiesSet()InitializingBeanspring-doc.cn

要解决此问题,您有两种选择:将缓存初始化策略更改为稍后阶段,或者确保先初始化密钥空间初始化器。spring-doc.cn

如果应用程序由您控制,则更改缓存初始化策略可能很容易。 有关如何实现此功能的一些建议包括:spring-doc.cn

  • 使缓存在首次使用时延迟初始化,从而缩短应用程序启动时间。spring-doc.cn

  • 让您的缓存或初始化缓存的单独组件实现 或 . 当应用程序上下文启动时,您可以通过设置其标志来自动启动 a,也可以通过调用封闭上下文来手动启动 a。LifecycleSmartLifecycleSmartLifecycleautoStartupLifecycleConfigurableApplicationContext.start()spring-doc.cn

  • 使用 Spring 或类似的自定义观察者机制来触发缓存初始化。 当它准备好使用时(在所有 bean 都已初始化之后),它总是由上下文发布,因此这通常是一个有用的钩子(这就是默认情况下的工作方式)。ApplicationEventContextRefreshedEventSmartLifecyclespring-doc.cn

确保首先初始化 keyspace initializer 也很容易。 有关如何实现此功能的一些建议包括:spring-doc.cn

  • 依赖 Spring 的默认行为,即 bean 按注册顺序初始化。 您可以通过在 XML 配置中采用一组对应用程序模块进行排序的元素的常见做法,并确保首先列出数据库和数据库初始化,从而轻松安排这一点。BeanFactory<import/>spring-doc.cn

  • 将 和 使用它的业务组件分开,并通过将它们放在单独的实例中来控制它们的启动顺序 (例如,父上下文包含 ,子上下文包含业务组件)。 这种结构在 Spring Web 应用程序中很常见,但可以更普遍地应用。SessionFactoryApplicationContextSessionFactoryspring-doc.cn

  • 使用 Schema management for Tables 和 User-defined Types 来使用 Spring Data Cassandra 的内置模式生成器初始化键空间。spring-doc.cn

表和用户定义的类型

Spring Data for Apache Cassandra 使用适合您数据模型的映射实体类进行数据访问。 您可以使用这些实体类来创建 Cassandra 表规范和用户类型定义。spring-doc.cn

架构创建与 初始化 相关联。 支持以下操作:CqlSessionSchemaActionspring-doc.cn

  • SchemaAction.NONE:不创建或删除任何表或类型。 这是默认设置。spring-doc.cn

  • SchemaAction.CREATE:从带有 . 如果尝试创建类型,则现有表或类型会导致错误。@Table@UserDefinedTypespring-doc.cn

  • SchemaAction.CREATE_IF_NOT_EXISTS:喜欢但应用了。 现有表或类型不会导致任何错误,但可能会保持过时。SchemaAction.CREATEIF NOT EXISTSspring-doc.cn

  • SchemaAction.RECREATE:删除并重新创建已知使用的现有表和类型。 未在应用程序中配置的表和类型不会被删除。spring-doc.cn

  • SchemaAction.RECREATE_DROP_UNUSED:删除所有表和类型,仅重新创建已知的表和类型。spring-doc.cn

SchemaAction.RECREATE并删除您的表并丢失所有数据。 还会删除应用程序未知的表和类型。SchemaAction.RECREATE_DROP_UNUSEDRECREATE_DROP_UNUSED

为 Schema Management 启用表和用户定义类型

基于元数据的映射 解释了使用约定和注释进行对象映射。 为防止将不需要的类创建为表或类型,架构管理仅对使用 注释的实体和使用 注释的用户定义类型处于活动状态。 通过扫描 Classpath 来发现实体。 实体扫描需要一个或多个基础包。 使用的元组类型列不提供任何类型详细信息。 因此,您必须对此类列属性进行注释,以指定所需的列类型。@Table@UserDefinedTypeTupleValue@CassandraType(type = TUPLE, typeArguments = …)spring-doc.cn

以下示例演示如何在 XML 配置中指定实体基础包:spring-doc.cn

例 5.指定实体基础包
Java
@Configuration
public class EntityBasePackagesConfiguration extends AbstractCassandraConfiguration {

	@Override
	public String[] getEntityBasePackages() {
		return new String[] { "com.foo", "com.bar" };
	}

	// ...
}
XML 格式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
  xsi:schemaLocation="
    http://www.springframework.org/schema/data/cassandra
    https://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd
    http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd">

    <cassandra:mapping entity-base-packages="com.foo,com.bar"/>
</beans>