Einführung in Spring Data Cassandra
1. Überblick
Dieser Artikel ist eine praktische Einführung in die Arbeit mit Cassandra mit Spring Data.
Wir beginnen mit den Grundlagen, gehen die Konfigurationen und die Codierung durch und bauen schließlich ein vollständiges Spring Data Cassandra-Modul auf.
2. Maven-Abhängigkeiten
Beginnen wir mit der Definition der Abhängigkeiten inpom.xml mit Maven:
com.datastax.cassandra
cassandra-driver-core
2.1.9
3. Konfiguration für Cassandra
Wir werden den Java-Konfigurationsstil verwenden, um die Cassandra-Integration zu konfigurieren.
3.1. Die Hauptkonfiguration
Beginnen wir mit der Hauptkonfigurationsklasse - natürlich gesteuert über die Sannotation@Configuration der Klassenstufe:
@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();
}
}
Beachten Sie die neue Bean -BasicCassandraMappingContext - mit einer Standardimplementierung. Dies ist erforderlich, um die persistenten Entitäten zwischen ihrem Objekt und ihren persistenten Formaten abzubilden.
Und da die Standardimplementierung ausreicht, können wir sie direkt verwenden.
3.2. Cassandra-Verbindungseigenschaften
Es gibt drei obligatorische Einstellungen, die konfiguriert werden müssen, um die Verbindung für einen Cassandra-Client einzurichten.
Wir müssen den Hostnamen so einrichten, dass der Cassandra-Server, der als contactPoints. Port ausgeführt wird, einfach der Überwachungsport für die Anforderung im Server ist. KeyspaceName ist der Namespace, der die Datenreplikation auf Knoten definiert und auf einem Cassandra-bezogenen Konzept basiert.
4. Das Cassandra-Repository
Wir werden einCassandraRepository für die Datenzugriffsschicht verwenden. Dies folgt auf die Spring Data Repository-Abstraktion, die sich darauf konzentriert, den für die Implementierung der Datenzugriffsschichten erforderlichen Code über verschiedene Persistenzmechanismen hinweg zu abstrahieren.
4.1. Erstellen Sie dieCassandraRepository
Erstellen wir dieCassandraRepository, die in der Konfiguration verwendet werden sollen:
@Repository
public interface BookRepository extends CassandraRepository {
//
}
4.2. Konfiguration fürCassandraRepository
Jetzt können wir die Konfiguration in Abschnitt 3.1 erweitern und Anmerkungen auf Klassenebene von@EnableCassandraRepositorieshinzufügen, um unser in Abschnitt 4.1 erstelltes Cassandra-Repository inCassandraConfig: zu markieren
@Configuration
@EnableCassandraRepositories(
basePackages = "org.example.spring.data.cassandra.repository")
public class CassandraConfig extends AbstractCassandraConfiguration {
//
}
5. Die Entität
Werfen wir einen kurzen Blick auf die Entität - die Modellklasse, die wir verwenden werden. Die Klasse ist mit Anmerkungen versehen und definiert zusätzliche Parameter für die Erstellung der Metadaten-Cassandra-Datentabelle im eingebetteten Modus.
Mit der Annotation@Tablewird die Bean direkt einer Cassandra-Datentabelle zugeordnet. Außerdem ist jede Eigenschaft als eine Art Primärschlüssel oder eine einfache Spalte definiert:
@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. Testen mit einem eingebetteten Server
6.1. Maven-Abhängigkeiten
Wenn Sie Cassandra im eingebetteten Modus ausführen möchten (ohne manuell einen separaten Cassandra-Server zu installieren), müssen Sie diecassandra-unit-abhängigen Abhängigkeiten zu denpom.xml hinzufügen:
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
Es ist möglich,use an embedded Cassandra server to test this application. Der Hauptvorteil ist, dass Sie Cassandra nicht explizit installieren möchten.
Dieser eingebettete Server ist auch mit Spring JUnit Tests kompatibel. Hier können wirSpringJUnit4ClassRunner mithilfe der Annotation@RunWith zusammen mit dem eingebetteten Server festlegen. So ist es möglich, eine vollständige Testsuite zu implementieren, ohne dass ein externer Cassandra-Dienst ausgeführt wird.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CassandraConfig.class)
public class BookRepositoryIntegrationTest {
//
}
6.2. Starten und Stoppen des Servers
Sie können diesen Abschnitt ignorieren, wenn Sie einen externen Cassandra-Server ausführen.
Wir müssen den Server einmal für die gesamte Testsuite starten, daher ist die Serverstartmethode mit der Anmerkung@BeforeClassgekennzeichnet:
@BeforeClass
public static void startCassandraEmbedded() {
EmbeddedCassandraServerHelper.startEmbeddedCassandra();
Cluster cluster = Cluster.builder()
.addContactPoints("127.0.0.1").withPort(9142).build();
Session session = cluster.connect();
}
Als Nächstes müssen wir sicherstellen, dass der Server nach Abschluss der Testsuite-Ausführung gestoppt wird:
@AfterClass
public static void stopCassandraEmbedded() {
EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}
6.3. Datentabelle bereinigen
Es wird empfohlen, die Datentabelle vor jeder Testausführung zu löschen und zu erstellen, um unerwartete Ergebnisse aufgrund manipulierter Daten in früheren Testausführungen zu vermeiden.
Jetzt können wir die Datentabelle erstellen, wenn der Server gestartet wird:
@Before
public void createTable() {
adminTemplate.createTable(
true, CqlIdentifier.cqlId(DATA_TABLE_NAME),
Book.class, new HashMap());
}
und nach jeder einzelnen Testfallausführung fallen lassen:
@After
public void dropTable() {
adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME));
}
7. Datenzugriff mitCassandraRepository
Wir können die oben erstelltenBookRepository direkt verwenden, um die Daten in der Cassandra-Datenbank beizubehalten, zu bearbeiten und abzurufen.
7.1. Speichern Sie ein neues Buch
Wir können ein neues Buch in unserer Buchhandlung speichern:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Dann können wir die Verfügbarkeit des eingefügten Buches in der Datenbank überprüfen:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertEquals(javaBook.getId(), books.iterator().next().getId());
7.2. Aktualisieren Sie ein vorhandenes Buch
Beginnen Sie mit dem Einfügen eines neuen Buches:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Holen wir uns das Buch nach dem Titel:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
Dann ändern wir den Titel des Buches:
javaBook.setTitle("Head First Java Second Edition");
bookRepository.save(ImmutableSet.of(javaBook));
Überprüfen wir abschließend, ob der Titel in der Datenbank aktualisiert wurde:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java Second Edition", "O'Reilly Media");
assertEquals(
javaBook.getTitle(), updateBooks.iterator().next().getTitle());
7.3. Löschen Sie das vorhandene Buch
Legen Sie ein neues Buch ein:
Book javaBook = new Book(
UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
Dann löschen Sie das neu eingegebene Buch:
bookRepository.delete(javaBook);
Jetzt können wir nach dem Löschen suchen:
Iterable books = bookRepository.findByTitleAndPublisher(
"Head First Java", "O'Reilly Media");
assertNotEquals(javaBook.getId(), books.iterator().next().getId());
Dadurch wird eine NoSuchElementException aus dem Code ausgelöst, um sicherzustellen, dass das Buch gelöscht wird.
7.4. Alle Bücher finden
Legen Sie zuerst ein neues Buch ein:
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));
Alle Bücher finden:
Iterable books = bookRepository.findAll();
Dann können wir die Anzahl der verfügbaren Bücher in der Datenbank überprüfen:
int bookCount = 0;
for (Book book : books) bookCount++;
assertEquals(bookCount, 2);
8. Fazit
Wir haben eine grundlegende praktische Einführung in die Cassandra mit Spring-Daten unter Verwendung des gängigsten Ansatzes unter Verwendung des Datenzugriffsmechanismus vonCassandraRepositorydurchlaufen.
Die Implementierung der obigen Codefragmente und Beispiele finden Sie inmy GitHub project - dies ist ein Eclipse-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.