1. Обзор
Эта статья представляет собой практическое введение в работу с Cassandra с Spring Data.
Мы начнем с основ и пройдемся по конфигурациям и кодированию, наконец, создадим полный модуль Spring Data Cassandra.
2. Зависимости Maven
Начнем с определения зависимостей в pom.xml
с помощью Maven:
<dependency>
<groupId>com.datastax.cassandra</groupId>
<artifactId>cassandra-driver-core</artifactId>
<version>2.1.9</version>
</dependency>
3. Конфигурация для Кассандры
Мы будем использовать стиль конфигурации Java для настройки интеграции с Cassandra.
3.1. Основная конфигурация (весна)
Для этого мы будем использовать стиль конфигурации Java. Давайте начнем с основного класса конфигурации — конечно, управляемого через аннотацию @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();
}
}
Обратите внимание на новый компонент — BasicCassandraMappingContext
— с реализацией по умолчанию. Это необходимо для сопоставления постоянных объектов между их объектом и их постоянными форматами.
И поскольку реализация по умолчанию достаточно функциональна, мы можем использовать ее напрямую.
3.2. Основная конфигурация (весенняя загрузка)
Настроим Cassandra через application.properties
:
spring.data.cassandra.keyspace-name=testKeySpace
spring.data.cassandra.port=9142
spring.data.cassandra.contact-points=127.0.0.1
И мы закончили! Это все, что нам нужно при использовании Spring Boot.
3.3. Свойства подключения Кассандры
Есть три обязательных параметра, которые мы должны настроить, чтобы установить соединение для клиента Cassandra.
Мы должны настроить имя хоста, на котором сервер Cassandra работает как контактные точки. Порт
— это просто прослушивающий порт для запроса на сервере. KeyspaceName
— это пространство имен, которое определяет репликацию данных на узлах, основанную на концепции, связанной с Cassandra.
4. Репозиторий Кассандры
Мы собираемся использовать CassandraRepository
для уровня доступа к данным. Это следует за абстракцией репозитория Spring Data, которая сосредоточена на абстрагировании кода, необходимого для реализации уровней доступа к данным в различных механизмах сохранения.
4.1. Создайте репозиторий CassandraRepository
Давайте создадим CassandraRepository
для использования в конфигурации:
@Repository
public interface BookRepository extends CassandraRepository<Book> {
//
}
4.2. Конфигурация CassandraRepository
Теперь мы можем расширить конфигурацию в разделе 3.1, добавив аннотацию уровня класса @EnableCassandraRepositories
, чтобы отметить наш репозиторий Cassandra, созданный в разделе 4.1 в CassandraConfig:
@Configuration
@EnableCassandraRepositories(
basePackages = "com.foreach.spring.data.cassandra.repository")
public class CassandraConfig extends AbstractCassandraConfiguration {
//
}
5. Сущность
Давайте быстро взглянем на сущность — класс модели, который мы собираемся использовать. Класс аннотирован и определяет дополнительные параметры для создания таблицы метаданных Cassandra во встроенном режиме.
Используя аннотацию @Table
, bean-компонент напрямую сопоставляется с таблицей данных Cassandra. Также каждое свойство определяется как тип первичного ключа или простого столбца:
@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<String> tags = new HashSet<>();
// standard getters and setters
}
6. Тестирование со встроенным сервером
6.1. Зависимости Maven
Если вы хотите запустить Cassandra во встроенном режиме (без ручной установки отдельного сервера Cassandra), вам необходимо добавить зависимости, связанные с cassandra -unit , в
pom.xml
:
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-spring</artifactId>
<version>2.1.9.2</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit-shaded</artifactId>
<version>2.1.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hectorclient</groupId>
<artifactId>hector-core</artifactId>
<version>2.0-0</version>
</dependency>
Для тестирования этого приложения можно использовать встроенный сервер Cassandra . Основное преимущество заключается в том, что вы не хотите устанавливать Cassandra явно.
Этот встроенный сервер также совместим с Spring JUnit Tests. Здесь мы можем установить SpringJUnit4ClassRunner
с помощью аннотации @RunWith
вместе со встроенным сервером. Таким образом, можно реализовать полный набор тестов без запуска внешней службы Cassandra.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
public class BookRepositoryIntegrationTest {
//
}
6.2. Запуск и остановка сервера
Вы можете игнорировать этот раздел, если вы используете внешний сервер Cassandra.
Мы должны запустить сервер один раз для всего набора тестов, поэтому метод запуска сервера помечен аннотацией @BeforeClass
:
@BeforeClass
public static void startCassandraEmbedded() {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
Cluster cluster = Cluster.builder()
.addContactPoints("127.0.0.1").withPort(9142).build();
Session session = cluster.connect();
}
Затем мы должны убедиться, что сервер остановлен после завершения выполнения набора тестов:
@AfterClass
public static void stopCassandraEmbedded() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}
6.3. Чистая таблица данных
Рекомендуется удалять и создавать таблицу данных перед каждым выполнением теста, чтобы избежать непредвиденных результатов из-за манипулирования данными в более ранних выполнениях теста.
Теперь мы можем создать таблицу данных при запуске сервера:
@Before
public void createTable() {
adminTemplate.createTable(
true, CqlIdentifier.cqlId(DATA_TABLE_NAME),
Book.class, new HashMap<String, Object>());
}
и отбрасывать после каждого выполнения тестового примера:
@After
public void dropTable() {
adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME));
}
7. Доступ к данным с помощью CassandraRepository
Мы можем напрямую использовать BookRepository
, созданный выше, для сохранения, обработки и извлечения данных из базы данных Cassandra.
7.1. Сохранить новую книгу
Мы можем сохранить новую книгу в наш книжный магазин:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Затем мы можем проверить наличие вставленной книги в базе данных:
Iterable<Book> books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertEquals(javaBook.getId(), books.iterator().next().getId());
7.2. Обновить существующую книгу
Начнем с вставки новой книги:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Выберем книгу по названию:
Iterable<Book> books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
Тогда давайте изменим название книги:
javaBook.setTitle("Head First Java Second Edition");
bookRepository.save(ImmutableSet.of(javaBook));
Наконец, давайте проверим, обновляется ли заголовок в базе данных:
Iterable<Book> books = bookRepository.findByTitleAndPublisher(
"Head First Java Second Edition", "O'Reilly Media");
assertEquals(
javaBook.getTitle(), updateBooks.iterator().next().getTitle());
7.3. Удалить существующую книгу
Вставьте новую книгу:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Затем удалите только что введенную книгу:
bookRepository.delete(javaBook);
Теперь мы можем проверить удаление:
Iterable<Book> books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertNotEquals(javaBook.getId(), books.iterator().next().getId());
Это вызовет исключение NoSuchElementException из кода, чтобы убедиться, что книга удалена.
7.4. Найти все книги
Сначала вставьте новые книги:
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));
Найти все книги:
Iterable<Book> books = bookRepository.findAll();
Затем мы можем проверить количество доступных книг в базе данных:
int bookCount = 0;
for (Book book : books) bookCount++;
assertEquals(bookCount, 2);
8. Заключение
Мы прошли базовое практическое введение в Cassandra с данными Spring, используя наиболее распространенный подход с использованием механизма доступа к данным CassandraRepository .
Реализацию приведенных выше фрагментов кода и примеры можно найти в моем проекте GitHub — это проект на основе Eclipse, поэтому его легко импортировать и запускать как есть.