【问题标题】:How to initialize Cassandra keyspace and tables with Spring boot如何使用 Spring Boot 初始化 Cassandra 键空间和表
【发布时间】:2016-05-10 20:40:02
【问题描述】:

我在 Spring Boot 应用程序中使用 Cassandra 作为数据源,并希望在应用程序启动之前初始化数据库。

到目前为止,我已经定义了一个扩展“AbstractCassandraConfiguration”类的“CassandraConfiguration”类,如下面的示例所示,我有一个扩展“CassandraRepository”的存储库。当我自己创建键空间和表时,应用程序运行良好。

但是,我想在应用程序启动时自动创建键空间和表。为此,我在资源文件夹下提供了一个 schema.cql 文件,但我无法使该脚本工作。

有谁知道我可以做些什么来自动创建键空间和表?

谢谢。

编辑:我正在使用 Cassandra 2.0.9、spring-boot 1.3.2.RELEASE 和 datastax cassandra 驱动程序 2.1.6 版本。

CassandraConfiguration.java

@Configuration
@PropertySource(value = { "classpath:cassandra.properties" })
@EnableCassandraRepositories(basePackages = { "bla.bla.bla.repository" })
public class CassandraConfiguration extends AbstractCassandraConfiguration {

    @Autowired
    private Environment environment;


    @Bean
    public CassandraClusterFactoryBean cluster() {
        CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
        cluster.setContactPoints( environment.getProperty( "cassandra.contactpoints" ) );
        cluster.setPort( Integer.parseInt( environment.getProperty( "cassandra.port" ) ) );
        return cluster;
    }


    @Bean
    public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
        return new BasicCassandraMappingContext();
    }


    @Bean
    public CassandraConverter converter() throws ClassNotFoundException {
        return new MappingCassandraConverter(cassandraMapping());
    }


    @Override
    protected String getKeyspaceName() {
        return environment.getProperty( "cassandra.keyspace" );
    }


    @Bean
    public CassandraSessionFactoryBean session() throws Exception {

        CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
        session.setCluster(cluster().getObject());
        session.setKeyspaceName(environment.getProperty("cassandra.keyspace"));
        session.setConverter(converter());
        session.setSchemaAction(SchemaAction.NONE);

        return session;
    }


    @Override
    public SchemaAction getSchemaAction() {
        return SchemaAction.RECREATE_DROP_UNUSED;
    }
}

【问题讨论】:

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


【解决方案1】:

如果您仍然遇到此问题,在 Spring Boot 2 和 SD Cassandra 2.0.3 中,您可以进行这种简单的 Java 配置并开箱即用地设置所有内容。

@Configuration
@EnableCassandraRepositories(basePackages = "com.example.repository")
public class DbConfigAutoStart extends AbstractCassandraConfiguration {

    /*
     * Provide a contact point to the configuration.
     */
    @Override
    public String getContactPoints() {
        return "exampleContactPointsUrl";
    }

    /*
     * Provide a keyspace name to the configuration.
     */
    @Override
    public String getKeyspaceName() {
        return "exampleKeyspace";
    }

    /*
     * Automatically creates a Keyspace if it doesn't exist
     */
    @Override
    protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
        CreateKeyspaceSpecification specification = CreateKeyspaceSpecification
                .createKeyspace("exampleKeyspace").ifNotExists()
                .with(KeyspaceOption.DURABLE_WRITES, true).withSimpleReplication();
        return Arrays.asList(specification);
    }


    /*
     * Automatically configure a table if doesn't exist
     */
    @Override
    public SchemaAction getSchemaAction() {
        return SchemaAction.CREATE_IF_NOT_EXISTS;
    }


    /*
     * Get the entity package (where the entity class has the @Table annotation)
     */
    @Override
    public String[] getEntityBasePackages() {
        return new String[] { "com.example.entity" };
    }

你很高兴

【讨论】:

  • 也适用于较低版本(spring boot 1.5.10 和 cassandra 3.0.16)。
【解决方案2】:

您的返回类型 BasicCassandraMappingContext() 可能已被弃用。使用

@Bean
public CassandraMappingContext mappingContext() throws ClassNotFoundException {
    CassandraMappingContext mappingContext= new CassandraMappingContext();
    mappingContext.setInitialEntitySet(getInitialEntitySet());
    return mappingContext;
}
@Override
public String[] getEntityBasePackages() {
    return new String[]{"base-package name of all your entity, annotated 
with @Table"};
}

@Override
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
    return CassandraEntityClassScanner.scan(getEntityBasePackages());
}

而不是,

@Bean
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
    return new BasicCassandraMappingContext();
}

还设置:

session.setSchemaAction(SchemaAction.RECREATE_DROP_UNUSED);

和排除:

@Override
public SchemaAction getSchemaAction() {
    return SchemaAction.RECREATE_DROP_UNUSED;
}

获取参考here

【讨论】:

    【解决方案3】:

    我正在使用spring-boot 1.5.10.RELEASEcassandra 3.0.16,但您可以尝试缩小版本。要创建密钥空间,您可以从 application.ymlapplication.properties 导入密钥空间名称。使用 @Table 注释,如果您设置了实体基础包,您的表应该会自动生成。

    @Value("${cassandra.keyspace}")
    private String keySpace;
    
    @Override
    public String[] getEntityBasePackages() {
        return new String[]{"com.example.your.entities"};
    }
    
    @Override
    protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
        return Arrays.asList(
                CreateKeyspaceSpecification.createKeyspace()
                        .name(keySpace)
                        .ifNotExists()
        );
    }
    

    【讨论】:

      【解决方案4】:

      最后我通过将 setKeyspaceCreations(getKeyspaceCreations()) 添加到 CassandraClusterFactoryBean 覆盖并确保启用 @ComponentScan 来使其工作。

      import com.datastax.driver.core.PlainTextAuthProvider;
      import com.datastax.driver.core.policies.ConstantReconnectionPolicy;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.data.cassandra.config.*;
      import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
      import org.springframework.data.cassandra.core.cql.keyspace.DropKeyspaceSpecification;
      import org.springframework.data.cassandra.core.cql.keyspace.KeyspaceOption;
      import org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;
      
      import java.util.Arrays;
      import java.util.List;
      
      
      
      @Configuration
      @EnableReactiveCassandraRepositories(basePackages = "com.company.domain.data")
      public class CassandraConfig extends AbstractReactiveCassandraConfiguration{
      @Value("${spring.data.cassandra.contactpoints}") private String contactPoints;
      @Value("${spring.data.cassandra.port}") private int port;
      @Value("${spring.data.cassandra.keyspace-name}") private String keyspace;
      
      @Value("${spring.data.cassandra.username}") private String userName;
      @Value("${spring.data.cassandra.password}") private String password;
      @Value("${cassandra.basepackages}") private String basePackages;
      
      
      @Override protected String getKeyspaceName() {
          return keyspace;
      }
      @Override protected String getContactPoints() {
          return contactPoints;
      }
      @Override protected int getPort() {
          return port;
      }
      @Override public SchemaAction getSchemaAction() {
          return SchemaAction.CREATE_IF_NOT_EXISTS;
      }
      @Override
      public String[] getEntityBasePackages() {
          return new String[]{"com.company.domain.data"};
      }
      
      @Override
      public CassandraClusterFactoryBean cluster() {
          PlainTextAuthProvider authProvider = new PlainTextAuthProvider(userName, password);
      
          CassandraClusterFactoryBean cluster=new CassandraClusterFactoryBean();
      
          cluster.setJmxReportingEnabled(false);
          cluster.setContactPoints(contactPoints);
          cluster.setPort(port);
          cluster.setAuthProvider(authProvider);
          cluster.setKeyspaceCreations(getKeyspaceCreations());
          cluster.setReconnectionPolicy(new ConstantReconnectionPolicy(1000));
      
          return cluster;
      }
      
      
      @Override
      protected List<CreateKeyspaceSpecification> getKeyspaceCreations() {
      
          CreateKeyspaceSpecification specification = CreateKeyspaceSpecification.createKeyspace(keyspace)
                  .ifNotExists()
                  .with(KeyspaceOption.DURABLE_WRITES, true);
      
          return Arrays.asList(specification);
      }
      
      
      
      @Override
      protected List<DropKeyspaceSpecification> getKeyspaceDrops() {
          return Arrays.asList(DropKeyspaceSpecification.dropKeyspace(keyspace));
      }
      
      
      
      }
      

      【讨论】:

        【解决方案5】:

        之前的答案基于来自spring-data-cassandraAbstractCassandraConfiguration。如果您使用spring-boot,那么它可以为您自动配置Cassandra,无需扩展AbstractCassandraConfiguration。但是,即使在这种情况下,您也需要做一些工作来自动创建密钥空间。我已经决定在我们公司的 spring-boot 启动器中添加一个自动配置,但您也可以在您的应用程序中将其定义为常规配置。

        /**
         * create the configured keyspace before the first cqlSession is instantiated. This is guaranteed by running this
         * autoconfiguration before the spring-boot one.
         */
        @ConditionalOnClass(CqlSession.class)
        @ConditionalOnProperty(name = "spring.data.cassandra.create-keyspace", havingValue = "true")
        @AutoConfigureBefore(CassandraAutoConfiguration.class)
        public class CassandraCreateKeyspaceAutoConfiguration {
        
            private static final Logger logger = LoggerFactory.getLogger(CassandraCreateKeyspaceAutoConfiguration.class);
        
            public CassandraCreateKeyspaceAutoConfiguration(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) {
                // It's OK to mutate cqlSessionBuilder because it has prototype scope.
                try (CqlSession session = cqlSessionBuilder.withKeyspace((CqlIdentifier) null).build()) {
                    logger.info("Creating keyspace {} ...", properties.getKeyspaceName());
                    session.execute(CreateKeyspaceCqlGenerator.toCql(
                            CreateKeyspaceSpecification.createKeyspace(properties.getKeyspaceName()).ifNotExists()));
                }
            }
        }
        

        在我的例子中,我还添加了一个配置属性来控制创建,spring.data.cassandra.create-keyspace,如果您不需要灵活性,可以省略它。

        请注意,spring-boot 自动配置取决于某些配置属性,这是我在开发环境中拥有的:

        spring:
          data:
            cassandra:
              keyspace-name: mykeyspace
              contact-points: 127.0.0.1
              port: 9042
              local-datacenter: datacenter1
              schema-action: CREATE_IF_NOT_EXISTS
              create-keyspace: true
        

        更多详情:spring-boot and Cassandra

        【讨论】:

          猜你喜欢
          • 2015-09-30
          • 1970-01-01
          • 2016-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-28
          • 2018-02-14
          • 1970-01-01
          相关资源
          最近更新 更多