Introdução ao Spring Data Cassandra
1. Visão geral
Este artigo é uma introdução prática ao trabalho com Cassandra com Spring Data.
Começaremos o básico e passaremos pelas configurações e codificação, finalmente construindo um módulo completo do Spring Data Cassandra.
2. Dependências do Maven
Vamos começar definindo as dependências empom.xml, com Maven:
com.datastax.cassandra
cassandra-driver-core
2.1.9
3. Configuração para Cassandra
Usaremos o estilo de configuração Java em todo este processo para configurar a integração do Cassandra.
3.1. A configuração principal
Vamos começar com a classe de configuração principal - claro, conduzida por meio da anotação de nível de classe@Configuration :
@Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {
@Override
protected String getKeyspaceName() {
return "testKeySpace";
}
@Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster =
new CassandraClusterFactoryBean();
cluster.setContactPoints("127.0.0.1");
cluster.setPort(9142);
return cluster;
}
@Bean
public CassandraMappingContext cassandraMapping()
throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
}
Observe o novo bean -BasicCassandraMappingContext - com uma implementação padrão. Isso é necessário para mapear as entidades persistentes entre seus objetos e seus formatos persistentes.
E como a implementação padrão é capaz o suficiente, podemos usá-la diretamente.
3.2. Propriedades de conexão Cassandra
Existem três configurações obrigatórias que precisamos definir para configurar a conexão para um cliente Cassandra.
Temos que configurar o nome do host para que o servidor Cassandra rodando como contactPoints. Port seja simplesmente a porta de escuta para solicitação no servidor. KeyspaceName é o namespace que define a replicação de dados em nós, que é baseado em um conceito relacionado ao Cassandra.
4. O Repositório Cassandra
Vamos usar umCassandraRepository para a camada de acesso a dados. Isso segue a abstração do repositório Spring Data, focada em abstrair o código necessário para implementar as camadas de acesso a dados em diferentes mecanismos de persistência.
4.1. Crie oCassandraRepository
Vamos criar oCassandraRepository para ser usado na configuração:
@Repository
public interface BookRepository extends CassandraRepository {
//
}
4.2. Configuração paraCassandraRepository
Agora, podemos estender a configuração na Seção 3.1, adicionando a anotação de nível de classe@EnableCassandraRepositories para marcar nosso Repositório Cassandra criado na seção 4.1 emCassandraConfig:
@Configuration
@EnableCassandraRepositories(
basePackages = "org.example.spring.data.cassandra.repository")
public class CassandraConfig extends AbstractCassandraConfiguration {
//
}
5. A entidade
Vamos dar uma olhada rápida na entidade - a classe de modelo que vamos usar. A classe é anotada e define parâmetros adicionais para a criação da tabela de dados do Cassandra de metadados no modo incorporado.
Usando a anotação@Table, o bean é diretamente mapeado para uma tabela de dados do Cassandra. Além disso, cada propriedade é definida como um tipo de chave primária ou uma coluna simples:
@Table
public class Book {
@PrimaryKeyColumn(
name = "isbn",
ordinal = 2,
type = PrimaryKeyType.CLUSTERED,
ordering = Ordering.DESCENDING)
private UUID id;
@PrimaryKeyColumn(
name = "title", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
private String title;
@PrimaryKeyColumn(
name = "publisher", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
private String publisher;
@Column
private Set tags = new HashSet<>();
// standard getters and setters
}
6. Testando com um servidor integrado
6.1. Dependências do Maven
Se você deseja executar o Cassandra no modo incorporado (sem instalar manualmente um servidor Cassandra separado), é necessário adicionar as dependências relacionadascassandra-unit aopom.xml:
org.cassandraunit
cassandra-unit-spring
2.1.9.2
test
org.cassandraunit
cassandra-unit
org.cassandraunit
cassandra-unit-shaded
2.1.9.2
test
org.hectorclient
hector-core
2.0-0
É possíveluse an embedded Cassandra server to test this application. A principal vantagem é que você não deseja instalar o Cassandra explicitamente.
Este servidor incorporado também é compatível com os testes Spring JUnit. Aqui podemos definirSpringJUnit4ClassRunner usando a anotação@RunWith junto com o servidor embutido. Portanto, é possível implementar um conjunto de testes completo sem a execução de um serviço Cassandra externo.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
public class BookRepositoryIntegrationTest {
//
}
6.2. Iniciando e parando o servidor
Você pode ignorar esta seção se estiver executando um servidor Cassandra externo.
Temos que iniciar o servidor uma vez para todo o conjunto de testes, então o método de início do servidor é marcado com a anotação@BeforeClass:
@BeforeClass
public static void startCassandraEmbedded() {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
Cluster cluster = Cluster.builder()
.addContactPoints("127.0.0.1").withPort(9142).build();
Session session = cluster.connect();
}
Em seguida, precisamos garantir que o servidor seja parado após a conclusão da execução do conjunto de testes:
@AfterClass
public static void stopCassandraEmbedded() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}
6.3. Limpar Tabela de Dados
É uma boa prática descartar e criar a tabela de dados antes de cada execução de teste, para evitar resultados inesperados devido aos dados manipulados nas execuções de teste anteriores.
Agora podemos criar a tabela de dados quando o servidor é iniciado:
@Before
public void createTable() {
adminTemplate.createTable(
true, CqlIdentifier.cqlId(DATA_TABLE_NAME),
Book.class, new HashMap());
}
e solte após cada execução de caso de teste:
@After
public void dropTable() {
adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME));
}
7. Acesso a dados usandoCassandraRepository
Podemos usar diretamente osBookRepository que criamos acima para persistir, manipular e buscar os dados no banco de dados do Cassandra.
7.1. Salvar um novo livro
Podemos salvar um novo livro em nossa livraria:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Em seguida, podemos verificar a disponibilidade do livro inserido no banco de dados:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertEquals(javaBook.getId(), books.iterator().next().getId());
7.2. Atualizar um livro existente
Lat's começa inserindo um novo livro:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Vamos buscar o livro pelo título:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
Então vamos mudar o título do livro:
javaBook.setTitle("Head First Java Second Edition");
bookRepository.save(ImmutableSet.of(javaBook));
Por fim, vamos verificar se o título está atualizado no banco de dados:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java Second Edition", "O'Reilly Media");
assertEquals(
javaBook.getTitle(), updateBooks.iterator().next().getTitle());
7.3. Exclua o livro existente
Insira um novo livro:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Em seguida, exclua o livro recém-inserido:
bookRepository.delete(javaBook);
Agora podemos verificar a exclusão:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertNotEquals(javaBook.getId(), books.iterator().next().getId());
Isso fará com que seja lançada uma NoSuchElementException do código, garantindo que o livro seja excluído.
7.4. Encontre todos os livros
Insira um novo livro primeiro:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
Book dPatternBook = new Book(
UUIDs.timeBased(), "Head Design Patterns","O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
bookRepository.save(ImmutableSet.of(dPatternBook));
Encontre todos os livros:
Iterable books = bookRepository.findAll();
Depois, podemos verificar o número de livros disponíveis no banco de dados:
int bookCount = 0;
for (Book book : books) bookCount++;
assertEquals(bookCount, 2);
8. Conclusão
Passamos por uma introdução prática básica ao Cassandra com dados Spring usando a abordagem mais comum usando o mecanismo de acesso a dadosCassandraRepository.
A implementação dos trechos de código e exemplos acima podem ser encontrados emmy GitHub project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.