Einführung zu Spring Data Couchbase

1. Einführung

In diesem Lernprogramm zu Spring Data erfahren Sie, wie Sie eine Persistenzschicht für Couchbase-Dokumente einrichten, indem Sie sowohl das Spring Data-Repository als auch die Vorlagenabstraktionen verwenden. Außerdem werden die erforderlichen Schritte zur Vorbereitung von Couchbase zur Unterstützung dieser Abstraktionen mit Ansichten und/oder Indizes beschrieben .

2. Abhängigkeiten von Maven

Zuerst fügen wir der Datei pom.xml die folgende Maven-Abhängigkeit hinzu:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-couchbase</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

Beachten Sie, dass wir durch das Einschließen dieser Abhängigkeit automatisch eine kompatible Version des nativen Couchbase-SDKs erhalten, sodass wir sie nicht explizit hinzufügen müssen.

Um die Unterstützung für die JSR-303-Bean-Validierung hinzuzufügen, schließen wir auch die folgende Abhängigkeit ein:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.4.Final</version>
</dependency>

Spring Data Couchbase unterstützt die Datums- und Zeitpersistenz über die traditionellen Date- und Calendar-Klassen sowie über die Joda Time-Bibliothek, die wir wie folgt enthalten:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.9.2</version>
</dependency>

3. Aufbau

Als Nächstes müssen Sie die Couchbase-Umgebung konfigurieren, indem Sie einen oder mehrere Knoten unseres Couchbase-Clusters sowie den Namen und das Kennwort des Buckets angeben, in dem wir unsere Dokumente speichern.

3.1. Java-Konfiguration

Für die Java-Klassenkonfiguration erweitern wir einfach die AbstractCouchbaseConfiguration -Klasse:

@Configuration
@EnableCouchbaseRepositories(basePackages={"org.baeldung.spring.data.couchbase"})
public class MyCouchbaseConfig extends AbstractCouchbaseConfiguration {

    @Override
    protected List<String> getBootstrapHosts() {
        return Arrays.asList("localhost");
    }

    @Override
    protected String getBucketName() {
        return "baeldung";
    }

    @Override
    protected String getBucketPassword() {
        return "";
    }
}

Wenn für Ihr Projekt mehr Anpassungen der Couchbase-Umgebung erforderlich sind, können Sie eine bereitstellen, indem Sie die Methode getEnvironment () überschreiben:

@Override
protected CouchbaseEnvironment getEnvironment() {
   ...
}

3.2. XML-Konfiguration

Hier ist die entsprechende Konfiguration in XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.springframework.org/schema/data/couchbase
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/data/couchbase
    http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd">

    <couchbase:cluster>
        <couchbase:node>localhost</couchbase:node>
    </couchbase:cluster>

    <couchbase:clusterInfo login="baeldung" password=""/>

    <couchbase:bucket bucketName="baeldung" bucketPassword=""/>

    <couchbase:repositories base-package="org.baeldung.spring.data.couchbase"/>
</beans:beans>

Hinweis: Der Knoten „ clusterInfo “ akzeptiert entweder Cluster-Anmeldeinformationen oder Bucket-Anmeldeinformationen und ist erforderlich , damit die Bibliothek feststellen kann, ob Ihr Couchbase-Cluster N1QL unterstützt (eine Obermenge von SQL für NoSQL-Datenbanken, verfügbar in Couchbase 4.0 und höher).

Wenn für Ihr Projekt eine benutzerdefinierte Couchbase-Umgebung erforderlich ist, können Sie eine mit dem Tag <couchbase: env/> bereitstellen.

4. Datenmodell

Erstellen Sie eine Entitätsklasse, die das zu persistierende JSON-Dokument darstellt.

Wir kommentieren die Klasse zuerst mit @ Document, und dann ein String -Feld mit @ Id , um den Couchbase-Dokumentschlüssel darzustellen.

Sie können entweder die Annotation @ Id von Spring Data oder die des ursprünglichen Couchbase-SDKs verwenden. Wenn Sie beide Annotationen @ Id in derselben Klasse in zwei verschiedenen Feldern verwenden, hat das mit der Annotation Spring Data @ Id annotierte Feld Vorrang und wird als Dokumentschlüssel verwendet.

Um die Attribute der JSON-Dokumente darzustellen, fügen wir private Member-Variablen hinzu, die mit @ Field versehen sind. Wir verwenden die Annotation @ NotNull , um bestimmte Felder als erforderlich zu kennzeichnen:

@Document
public class Person {
    @Id
    private String id;

    @Field
    @NotNull
    private String firstName;

    @Field
    @NotNull
    private String lastName;

    @Field
    @NotNull
    private DateTime created;

    @Field
    private DateTime updated;

   //standard getters and setters
}

Beachten Sie, dass die mit @ Id annotierte Eigenschaft lediglich den Dokumentschlüssel darstellt und nicht notwendigerweise Teil des gespeicherten JSON-Dokuments ist, es sei denn, sie wird auch mit @ Field wie in:

@Id
@Field
private String id;

Wenn Sie ein Feld in der Entitätsklasse anders benennen möchten als das, was im JSON-Dokument gespeichert werden soll, qualifizieren Sie einfach die Annotation @ Field wie in diesem Beispiel:

@Field("fname")
private String firstName;

Hier ist ein Beispiel, das zeigt, wie ein persistentes Person -Dokument aussehen würde:

{
    "firstName": "John",
    "lastName": "Smith",
    "created": 1457193705667
    "__class": "org.baeldung.spring.data.couchbase.model.Person"
}

Beachten Sie, dass Spring Data jedem Dokument automatisch ein Attribut hinzufügt, das den vollständigen Klassennamen der Entität enthält. Standardmäßig heißt dieses Attribut " class" , obwohl Sie dies in Ihrer Couchbase-Konfigurationsklasse überschreiben können, indem Sie die typeKey () - Methode überschreiben.

Wenn Sie beispielsweise ein Feld mit dem Namen "Datentyp" für die Klassennamen festlegen möchten, fügen Sie dies Ihrer Couchbase-Konfigurationsklasse hinzu:

@Override
public String typeKey() {
    return "dataType";
}

Ein weiterer häufiger Grund, typeKey () zu überschreiben, ist, wenn Sie eine Version von Couchbase Mobile verwenden, die keine Felder unterstützt, deren Unterstrich vorangestellt ist. In diesem Fall können Sie wie im vorherigen Beispiel ein eigenes Feld für den alternativen Typ auswählen oder ein anderes von Spring bereitgestelltes Feld verwenden:

@Override
public String typeKey() {
   //use "javaClass" instead of "__class"
    return MappingCouchbaseConverter.TYPEKEY__SYNCGATEWAY__COMPATIBLE;
}

5. Couchbase-Repository

Spring Data Couchbase bietet dieselben integrierten Abfragen und abgeleiteten Abfragemechanismen wie andere Spring Data-Module wie JPA.

Wir deklarieren ein Repository-Interface für die Person -Klasse, indem wir CrudRepository <String, Person> erweitern und eine ableitbare Abfragemethode hinzufügen:

public interface PersonRepository extends CrudRepository<Person, String> {
    List<Person> findByFirstName(String firstName);
}

6. N1QL-Unterstützung über Indizes

Wenn Sie Couchbase 4.0 oder höher verwenden, werden benutzerdefinierte Abfragen standardmäßig mit der N1QL-Engine verarbeitet (es sei denn, die entsprechenden Repository-Methoden sind mit @ View kommentiert, um die Verwendung von Sicherungsansichten anzugeben, wie im nächsten Abschnitt beschrieben.

Um Unterstützung für N1QL hinzuzufügen, müssen Sie einen primären Index für den Bucket erstellen.

Sie können den Index erstellen, indem Sie den cbq -Befehlszeilen-Abfrageprozessor verwenden (Informationen zum Starten des cbq -Tools für Ihre Umgebung finden Sie in Ihrer Couchbase-Dokumentation) und geben Sie den folgenden Befehl aus:

CREATE PRIMARY INDEX ON baeldung USING GSI;

Im obigen Befehl steht GSI für global secondary index , einen Typ von Index, der besonders für die Optimierung von Ad-hoc-N1QL-Abfragen zur Unterstützung von OLTP-Systemen geeignet ist. Sofern nicht anders angegeben, ist er der Standard-Indextyp.

Im Gegensatz zu auf Ansichten basierenden Indizes werden GSI-Indizes nicht automatisch über alle Indexknoten in einem Cluster repliziert. Wenn Ihr Cluster mehr als einen Indexknoten enthält, müssen Sie jeden GSI-Index auf jedem Knoten im Cluster erstellen und angeben auf jedem Knoten einen anderen Indexnamen.

Sie können auch einen oder mehrere Sekundärindizes erstellen. Wenn Sie dies tun, verwendet Couchbase sie nach Bedarf, um die Abfrageverarbeitung zu optimieren.

Um beispielsweise einen Index für das Feld firstName hinzuzufügen, geben Sie im cbq -Tool den folgenden Befehl ein:

CREATE INDEX idx__firstName ON baeldung(firstName) USING GSI;

7. Hintergrundansichten

Für jede Repository-Schnittstelle müssen Sie ein Couchbase-Designdokument und eine oder mehrere Ansichten im Zielbereich erstellen. Der Name des Designdokuments muss die lowerCamelCase -Version des Entitätsklassennamens sein (z. B. „Person“ ).

Unabhängig davon, welche Version von Couchbase Server Sie ausführen, müssen Sie eine Sicherungsansicht mit dem Namen "all" erstellen, um die integrierte Repository-Methode " findAll" zu unterstützen. Hier ist die Kartenfunktion für die "all" -Ansicht für unsere Person__-Klasse:

function (doc, meta) {
    if(doc.__class == "org.baeldung.spring.data.couchbase.model.Person") {
        emit(meta.id, null);
    }
}

Benutzerdefinierte Repository-Methoden müssen jeweils eine Hintergrundansicht haben, wenn Sie eine Couchbase-Version vor 4.0 verwenden.

Sichtunterstützte benutzerdefinierte Methoden müssen wie im folgenden Beispiel mit @ View kommentiert werden:

@View
List<Person> findByFirstName(String firstName);

Die Standardbenennungskonvention für Sicherungsansichten besteht in der Verwendung der lowerCamelCase -Version dieses Teils des Methodennamens nach dem Schlüsselwort " find" (z. B. "byFirstName" __).

So schreiben Sie die Kartenfunktion für die __-Ansicht "byFirstName":

function (doc, meta) {
    if(doc.__class == "org.baeldung.spring.data.couchbase.model.Person"
      && doc.firstName) {
        emit(doc.firstName, null);
    }
}

Sie können diese Namenskonvention überschreiben und Ihre eigenen Ansichtsnamen verwenden, indem Sie jede @ View -Anmerkung mit dem Namen der entsprechenden Hintergrundansicht qualifizieren. Zum Beispiel:

@View("myCustomView")
List<Person> findByFirstName(String lastName);

8. Service Layer

Für unsere Serviceebene definieren wir eine Schnittstelle und zwei Implementierungen:

eine mit der Spring Data-Repository-Abstraktion und eine andere mit der Spring Data-Vorlagenabstraktion. Hier ist unser PersonService Interface:

public interface PersonService {
    Person findOne(String id);
    List<Person> findAll();
    List<Person> findByFirstName(String firstName);

    void create(Person person);
    void update(Person person);
    void delete(Person person);
}

8.1. Repository-Service

Hier ist eine Implementierung mit dem oben definierten Repository:

@Service
@Qualifier("PersonRepositoryService")
public class PersonRepositoryService implements PersonService {

    @Autowired
    private PersonRepository repo;

    public Person findOne(String id) {
        return repo.findOne(id);
    }

    public List<Person> findAll() {
        List<Person> people = new ArrayList<Person>();
        Iterator<Person> it = repo.findAll().iterator();
        while(it.hasNext()) {
            people.add(it.next());
        }
        return people;
    }

    public List<Person> findByFirstName(String firstName) {
        return repo.findByFirstName(firstName);
    }

    public void create(Person person) {
        person.setCreated(DateTime.now());
        repo.save(person);
    }

    public void update(Person person) {
        person.setUpdated(DateTime.now());
        repo.save(person);
    }

    public void delete(Person person) {
        repo.delete(person);
    }
}

8.2. Vorlagenservice

Für die vorlagenbasierte Implementierung müssen wir die in Abschnitt 7 oben aufgeführten Unterstützungsansichten erstellen. Das CouchbaseTemplate -Objekt ist in unserem Spring-Kontext verfügbar und kann in die Serviceklasse eingefügt werden.

Hier ist die Implementierung unter Verwendung der Vorlagenabstraktion:

@Service
@Qualifier("PersonTemplateService")
public class PersonTemplateService implements PersonService {
    private static final String DESIGN__DOC = "person";
    @Autowired
    private CouchbaseTemplate template;

    public Person findOne(String id) {
       return template.findById(id, Person.class);
    }

    public List<Person> findAll() {
        return template.findByView(ViewQuery.from(DESIGN__DOC, "all"), Person.class);
    }

    public List<Person> findByFirstName(String firstName) {
        return template.findByView(ViewQuery.from(DESIGN__DOC, "byFirstName"), Person.class);
    }

    public void create(Person person) {
        person.setCreated(DateTime.now());
        template.insert(person);
    }

    public void update(Person person) {
        person.setUpdated(DateTime.now());
        template.update(person);
    }

    public void delete(Person person) {
        template.remove(person);
    }
}

9. Fazit

Wir haben gezeigt, wie Sie ein Projekt für die Verwendung des Spring Data Couchbase-Moduls konfigurieren und wie Sie eine einfache Entitätsklasse und ihre Repository-Schnittstelle schreiben. Wir haben eine einfache Serviceschnittstelle geschrieben und eine Implementierung mit dem Repository und eine andere Implementierung mit der Spring Data-Vorlagen-API bereitgestellt.

Den vollständigen Quellcode für dieses Lernprogramm können Sie unter https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-couchbase-2 (GitHub-Projekt) anzeigen.

Weitere Informationen finden Sie auf der Projektseite Spring Data Couchbase .