Einführung in Spring Data Cassandra

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.